home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / vm / sun4c.md / vmSun.c < prev    next >
C/C++ Source or Header  |  1991-08-09  |  165KB  |  5,744 lines

  1. /*
  2.  * vmSun.c -
  3.  *
  4.  *         This file contains all hardware-dependent vm C routines for Sun2's, 3's 
  5.  *    and 4's.  I will not attempt to explain the Sun mapping hardware in 
  6.  *    here.  See the sun architecture manuals for details on
  7.  *    the mapping hardware.
  8.  *
  9.  * Copyright 1990 Regents of the University of California
  10.  * Permission to use, copy, modify, and distribute this
  11.  * software and its documentation for any purpose and without
  12.  * fee is hereby granted, provided that the above copyright
  13.  * notice appear in all copies.  The University of California
  14.  * makes no representations about the suitability of this
  15.  * software for any purpose.  It is provided "as is" without
  16.  * express or implied warranty.
  17.  */
  18.  
  19. #ifndef lint
  20. static char rcsid[] = "$Header: /sprite/src/kernel/vm/sun4.md/RCS/vmSun.c,v 9.33 91/08/09 15:03:08 shirriff Exp $ SPRITE (Berkeley)";
  21. #endif not lint
  22.  
  23. #include <sprite.h>
  24. #include <vmSunConst.h>
  25. #include <machMon.h>
  26. #include <vm.h>
  27. #include <vmInt.h>
  28. #include <vmMach.h>
  29. #include <vmMachInt.h>
  30. #include <vmTrace.h>
  31. #include <list.h>
  32. #include <mach.h>
  33. #include <proc.h>
  34. #include <sched.h>
  35. #include <stdlib.h>
  36. #include <sync.h>
  37. #include <sys.h>
  38. #include <dbg.h>
  39. #include <net.h>
  40. #include <stdio.h>
  41. #include <bstring.h>
  42.  
  43. #if (MACH_MAX_NUM_PROCESSORS == 1) /* uniprocessor implementation */
  44. #undef MASTER_LOCK
  45. #undef MASTER_UNLOCK
  46. #define MASTER_LOCK(x) DISABLE_INTR()
  47. #define MASTER_UNLOCK(x) ENABLE_INTR()
  48. #else
  49.  
  50. /*
  51.  * The master lock to synchronize access to pmegs and context.
  52.  */
  53. static Sync_Semaphore vmMachMutex;
  54. static Sync_Semaphore *vmMachMutexPtr = &vmMachMutex;
  55. #endif
  56.  
  57. #ifndef sun4c
  58. /*
  59.  * Macros to translate from a virtual page to a physical page and back.
  60.  * For the sun4c, these are no longer macros, since they are much more
  61.  * complicated due to physical memory no longer being contiguous.  For
  62.  * speed perhaps someday they should be converted to complicated macros
  63.  * instead of functions.
  64.  */
  65. #define VirtToPhysPage(pfNum) ((pfNum) << VMMACH_CLUSTER_SHIFT)
  66. #define PhysToVirtPage(pfNum) ((pfNum) >> VMMACH_CLUSTER_SHIFT)
  67. #endif
  68.  
  69. extern int debugVmStubs; /* Unix compat debug flag. */
  70.  
  71. /*
  72.  * Convert from page to hardware segment, with correction for
  73.  * any difference between virtAddrPtr offset and segment offset.
  74.  * (This difference will only happen for shared segments.)
  75. */
  76. #define PageToOffSeg(page,virtAddrPtr) (PageToSeg((page)- \
  77.     segOffset(virtAddrPtr)+(virtAddrPtr->segPtr->offset)))
  78.  
  79. extern    Address    vmStackEndAddr;
  80.  
  81. static int GetNumPages _ARGS_((void));
  82. static int GetNumValidPages _ARGS_((Address virtAddr));
  83. static void FlushValidPages _ARGS_ ((Address virtAddr));
  84. #ifdef sun4c
  85. static int VirtToPhysPage _ARGS_((int pfNum));
  86. static int PhysToVirtPage _ARGS_((int pfNum));
  87. static void VmMachSetSegMapInContext _ARGS_((unsigned int context,
  88.     Address addr, unsigned int pmeg));
  89. #ifdef NOTDEF
  90. static void MapColorMapAndIdRomAddr _ARGS_((void));
  91. #endif /* NOTDEF */
  92. #endif /* sun4c */
  93. static void MMUInit _ARGS_((int firstFreeSegment));
  94. ENTRY static void CopySegData _ARGS_((register Vm_Segment *segPtr,
  95.     register VmMach_SegData *oldSegDataPtr,
  96.     register VmMach_SegData *newSegDataPtr));
  97. static void SegDelete _ARGS_((Vm_Segment *segPtr));
  98. INTERNAL static int PMEGGet _ARGS_((Vm_Segment  *softSegPtr, int hardSegNum,
  99.     Boolean flags));
  100. INTERNAL static void PMEGFree _ARGS_((int pmegNum));
  101. ENTRY static Boolean PMEGLock _ARGS_ ((register VmMach_SegData *machPtr,
  102.     int segNum));
  103. INTERNAL static void SetupContext _ARGS_((register Proc_ControlBlock
  104.     *procPtr));
  105. static void InitNetMem _ARGS_((void));
  106. static void FlushWholeCache _ARGS_((void));
  107. ENTRY static void WriteHardMapSeg _ARGS_((VmMach_ProcData *machPtr));
  108. static void PageInvalidate _ARGS_((register Vm_VirtAddr *virtAddrPtr,
  109.     unsigned int virtPage, Boolean segDeletion));
  110. INTERNAL static void DevBufferInit _ARGS_((void));
  111. static void VmMachTracePage _ARGS_((register VmMachPTE pte,
  112.     unsigned int pageNum));
  113. static void VmMachTrap _ARGS_((void));
  114. #ifndef sun4c
  115. INTERNAL static void Dev32BitDMABufferInit _ARGS_((void));
  116. #endif
  117.  
  118. /*----------------------------------------------------------------------
  119.  * 
  120.  *             Hardware data structures
  121.  *
  122.  * Terminology: 
  123.  *    1) Physical page frame: A frame that contains one hardware page.
  124.  *    2) Virtual page frame:  A frame that contains VMMACH_CLUSTER_SIZE 
  125.  *                hardware pages.
  126.  *    3) Software segment: The segment structure used by the hardware
  127.  *                 independent VM module.
  128.  *    4) Hardware segment: A piece of a hardware context.
  129.  *
  130.  * A hardware context corresponds to a process's address space.  A context
  131.  * is made up of many equal sized hardware segments.  The 
  132.  * kernel is mapped into each hardware context so that the kernel has easy
  133.  * access to user data.  One context (context 0) is reserved for use by
  134.  * kernel processes.  The hardware contexts are defined by the array
  135.  * contextArray which contains an entry for each context.  Each entry 
  136.  * contains a pointer back to the process that is executing in the context 
  137.  * and an array which is an exact duplicate of the hardware segment map for
  138.  * the context.  The contexts are managed by keeping all contexts except for
  139.  * the system context in a list that is kept in LRU order.  Whenever a context 
  140.  * is needed the first context off of the list is used and the context is
  141.  * stolen from the current process that owns it if necessary.
  142.  *
  143.  * PMEGs are allocated to software segments in order to allow pages to be mapped
  144.  * into the segment's virtual address space. There are only a few hundred
  145.  * PMEGs, which have to be shared by all segments.  PMEGs that have
  146.  * been allocated to user segments can be stolen at any time.  PMEGs that have
  147.  * been allocated to the system segment cannot be taken away unless the system
  148.  * segment voluntarily gives it up.  In order to manage the PMEGs there are
  149.  * two data structures.  One is an array of PMEG info structures that contains
  150.  * one entry for each PMEG.  The other is an array stored with each software
  151.  * segment struct that contains the PMEGs that have been allocated to the
  152.  * software segment.  Each entry in the array of PMEG info structures
  153.  * contains enough information to remove the PMEG from its software segment.
  154.  * One of the fields in the PMEG info struct is the count of pages that have
  155.  * been validated in the PMEG.  This is used to determine when a PMEG is no
  156.  * longer being actively used.  
  157.  *
  158.  * There are two lists that are used to manage PMEGs.  The pmegFreeList 
  159.  * contains all PMEGs that are either not being used or contain no valid 
  160.  * page map entries; unused ones are inserted at the front of the list 
  161.  * and empty ones at the rear.  The pmegInuseList contains all PMEGs
  162.  * that are being actively used to map user segments and is managed as a FIFO.
  163.  * PMEGs that are being used to map tbe kernel's VAS do not appear on the 
  164.  * pmegInuseList. When a pmeg is needed to map a virtual address, first the
  165.  * free list is checked.  If it is not empty then the first PMEG is pulled 
  166.  * off of the list.  If it is empty then the first PMEG is pulled off of the
  167.  * inUse list.  If the PMEG  that is selected is being used (either actively 
  168.  * or inactively) then it is freed from the software segment that is using it.
  169.  * Once the PMEG is freed up then if it is being allocated for a user segment
  170.  * it is put onto the end of the pmegInuseList.
  171.  *
  172.  * Page frames are allocated to software segments even when there is
  173.  * no PMEG to map it in.  Thus when a PMEG that was mapping a page needs to
  174.  * be removed from the software segment that owns the page, the reference
  175.  * and modify bits stored in the PMEG for the page must be saved.  The
  176.  * array refModMap is used for this.  It contains one entry for each
  177.  * virtual page frame.  Its value for a page frame or'd with the bits stored
  178.  * in the PMEG (if any) comprise the referenced and modified bits for a 
  179.  * virtual page frame.
  180.  * 
  181.  * IMPORTANT SYNCHRONIZATION NOTE:
  182.  *
  183.  * The internal data structures in this file have to be protected by a
  184.  * master lock if this code is to be run on a multi-processor.  Since a
  185.  * process cannot start executing unless VmMach_SetupContext can be
  186.  * executed first, VmMach_SetupContext cannot context switch inside itself;
  187.  * otherwise a deadlock will occur.  However, VmMach_SetupContext mucks with
  188.  * contexts and PMEGS and therefore would have to be synchronized
  189.  * on a multi-processor.  A monitor lock cannot be used because it may force
  190.  * VmMach_SetupContext to be context switched.
  191.  *
  192.  * The routines in this file also muck with other per segment data structures.
  193.  * Access to these data structures is synchronized by our caller (the
  194.  * machine independent module).
  195.  *
  196.  *----------------------------------------------------------------------
  197.  */
  198.  
  199. /*
  200.  * Machine dependent flags for the flags field in the Vm_VirtAddr struct.
  201.  * We are only allowed to use the second byte of the flags.
  202.  *
  203.  *    USING_MAPPED_SEG        The parsed virtual address falls into
  204.  *                    the mapping segment.
  205.  */
  206. #define    USING_MAPPED_SEG    0x100
  207.  
  208. /*
  209.  * Macros to get to and from hardware segments and pages.
  210.  */
  211. #define PageToSeg(page) ((page) >> (VMMACH_SEG_SHIFT - VMMACH_PAGE_SHIFT))
  212. #define SegToPage(seg) ((seg) << (VMMACH_SEG_SHIFT - VMMACH_PAGE_SHIFT))
  213.  
  214. /*
  215.  * Macro to set all page map entries for the given virtual address.
  216.  */
  217. #if (VMMACH_CLUSTER_SIZE == 1) 
  218. #define    SET_ALL_PAGE_MAP(virtAddr, pte) { \
  219.     VmMachSetPageMap((Address)(virtAddr), (pte)); \
  220. }
  221. #else
  222. #define    SET_ALL_PAGE_MAP(virtAddr, pte) { \
  223.     int    __i; \
  224.     for (__i = 0; __i < VMMACH_CLUSTER_SIZE; __i++) { \
  225.     VmMachSetPageMap((virtAddr) + __i * VMMACH_PAGE_SIZE_INT, (pte) + __i); \
  226.     } \
  227. }
  228. #endif
  229. /*
  230.  * PMEG segment info list entry.
  231.  */
  232. struct PMEGseg {
  233.     struct PMEGseg    *nextLink;    /* Linked list ptr. */
  234.     struct Vm_Segment    *segPtr;    /* Software segment. */
  235.     int            hardSegNum;    /* Hardware segment number. */
  236. };
  237.  
  238. /*
  239.  * PMEG table entry structure.
  240.  */
  241. typedef struct {
  242.     List_Links            links;        /* Links so that the pmeg */
  243.                                   /* can be in a list */
  244.     struct PMEGseg        segInfo;    /* Info on software segment. */
  245.     int                pageCount;    /* Count of resident pages in
  246.                          * this pmeg. */
  247.     int                lockCount;    /* The number of times that
  248.                          * this PMEG has been locked.*/
  249.     int                flags;        /* Flags defined below. */
  250. } PMEG;
  251.  
  252. /*
  253.  * Flags to indicate the state of a pmeg.
  254.  *
  255.  *    PMEG_DONT_ALLOC    This pmeg should not be reallocated.  This is 
  256.  *            when a pmeg cannot be reclaimed until it is
  257.  *            voluntarily freed.
  258.  *    PMEG_NEVER_FREE    Don't ever free this pmeg no matter what anybody says.
  259.  */
  260. #define    PMEG_DONT_ALLOC        0x1
  261. #define    PMEG_NEVER_FREE        0x2
  262.  
  263. /*
  264.  * Pmeg information.  pmegArray contains one entry for each pmeg.  pmegFreeList
  265.  * is a list of all pmegs that aren't being actively used.  pmegInuseList
  266.  * is a list of all pmegs that are being actively used.
  267.  */
  268. static    PMEG           pmegArray[VMMACH_NUM_PMEGS];
  269. static    List_Links       pmegFreeListHeader;
  270. static    List_Links       *pmegFreeList = &pmegFreeListHeader;
  271. static    List_Links       pmegInuseListHeader;
  272. static    List_Links       *pmegInuseList = &pmegInuseListHeader;
  273.  
  274. /*
  275.  * The context table structure.
  276.  */
  277. typedef struct VmMach_Context {
  278.     List_Links            links;     /* Links so that the contexts can be
  279.                          in a list. */
  280.     struct Proc_ControlBlock    *procPtr;    /* A pointer to the process
  281.                          * table entry for the process
  282.                          * that is running in this
  283.                          * context. */
  284.     VMMACH_SEG_NUM        map[VMMACH_NUM_SEGS_PER_CONTEXT];
  285.                     /* A reflection of the hardware context
  286.                      * map. */
  287.     unsigned int        context;/* Which context this is. */
  288.     int                flags;    /* Defined below. */
  289. } VmMach_Context;
  290.  
  291. /*
  292.  * Context flags:
  293.  *
  294.  *         CONTEXT_IN_USE    This context is used by a process.
  295.  */
  296. #define    CONTEXT_IN_USE    0x1
  297.  
  298. /*
  299.  * Context information.  contextArray contains one entry for each context. 
  300.  * contextList is a list of contexts in LRU order.
  301.  */
  302. static    VmMach_Context    contextArray[VMMACH_NUM_CONTEXTS];
  303. static    List_Links       contextListHeader;
  304. static    List_Links       *contextList = &contextListHeader;
  305.  
  306. /*
  307.  * Map containing one entry for each virtual page.
  308.  */
  309. static    VmMachPTE        *refModMap;
  310.  
  311. /*
  312.  * Macro to get a pointer into a software segment's hardware segment table.
  313.  */
  314. #ifdef CLEAN
  315. #define GetHardSegPtr(machPtr, segNum) \
  316.     ((machPtr)->segTablePtr + (segNum) - (machPtr)->offset)
  317. #else
  318. #define GetHardSegPtr(machPtr, segNum) \
  319.     ( ((unsigned)((segNum) - (machPtr)->offset) > (machPtr)->numSegs) ? \
  320.     (panic("Invalid segNum\n"),(machPtr)->segTablePtr) : \
  321.     ((machPtr)->segTablePtr + (segNum) - (machPtr)->offset) )
  322. #endif
  323.  
  324. /*
  325.  * Macro to check to see if address is in a hardware segment (PMEG) that
  326.  * is used by file cache virtual addresses.
  327.  * These kernel segment pmegs may be stolen.
  328.  */
  329.  
  330. #define    _ROUND2SEG(x) ((unsigned int)(x)  & ~(VMMACH_SEG_SIZE-1))
  331. #define    IN_FILE_CACHE_SEG(addr)                          \
  332.           ( ((unsigned int)(addr) >=                         \
  333.         _ROUND2SEG(vmBlockCacheBaseAddr + (VMMACH_SEG_SIZE-1))) &&   \
  334.         ((unsigned int)(addr) < _ROUND2SEG(vmBlockCacheEndAddr)) )
  335.  
  336. /*
  337.  * TRUE if stealing of file cache pmegs are permitted. Initialized to FALSE
  338.  * for backward compat with old file cache code.
  339.  */
  340. Boolean vmMachCanStealFileCachePmegs = FALSE;
  341.  
  342. /*
  343.  * The maximum amount of kernel code + data available.  This is set to however
  344.  * big you want it to be to make sure that the kernel heap has enough memory
  345.  * for all the file handles, etc.
  346.  */
  347. #ifdef sun2
  348. int    vmMachKernMemSize = 2048 * 1024;
  349. #endif
  350. #ifdef sun3
  351. int     vmMachKernMemSize = 8192 * 1024;
  352. #endif
  353. #ifdef sun4
  354. int    vmMachKernMemSize = 32 * 1024 * 1024;
  355. #endif
  356.  
  357. /*
  358.  * The segment that is used to map a segment into a process's virtual address
  359.  * space for cross-address-space copies.
  360.  */
  361. #define    MAP_SEG_NUM (((unsigned int) VMMACH_MAP_SEG_ADDR) >> VMMACH_SEG_SHIFT)
  362.  
  363. static    VmMach_SegData    *sysMachPtr;
  364. Address            vmMachPTESegAddr;
  365. Address            vmMachPMEGSegAddr;
  366.  
  367. static    Boolean        printedSegTrace;
  368. static    PMEG        *tracePMEGPtr;
  369.  
  370. #ifdef sun4c
  371. /*
  372.  * Structure for mapping virtual page frame numbers to physical page frame
  373.  * numbers and back for each memory board.
  374.  */
  375. typedef struct    {
  376.     unsigned int    endVirPfNum;    /* Ending virtual page frame nmber
  377.                      * on board. */
  378.     unsigned int    startVirPfNum;    /* Starting virtual page frame number
  379.                      * on board. */
  380.     unsigned int    physStartAddr;    /* Physical address of page frame. */
  381.     unsigned int    physEndAddr;    /* End physical address of page frame.*/
  382. } Memory_Board;
  383.  
  384. /*
  385.  * Pointer to board after last configured Memory board structure.
  386.  */
  387. static    Memory_Board    *lastMemBoard;
  388.  
  389. /*
  390.  * Memory_Board structures for each board in the system.  This array is sorted
  391.  * by endVirPfNum.
  392.  */
  393. static    Memory_Board    Mboards[6];
  394. #endif /* sun4c */
  395.  
  396.  
  397. /*
  398.  * ----------------------------------------------------------------------------
  399.  *
  400.  * VmMach_BootInit --
  401.  *
  402.  *      Do hardware dependent boot time initialization.
  403.  *
  404.  * Results:
  405.  *      None.
  406.  *
  407.  * Side effects:
  408.  *      Hardware page map for the kernel is initialized.  Also the various size
  409.  *     fields are filled in.
  410.  *
  411.  * ----------------------------------------------------------------------------
  412.  */
  413. void
  414. VmMach_BootInit(pageSizePtr, pageShiftPtr, pageTableIncPtr, kernMemSizePtr,
  415.         numKernPagesPtr, maxSegsPtr, maxProcessesPtr)
  416.     int    *pageSizePtr;
  417.     int    *pageShiftPtr;
  418.     int    *pageTableIncPtr;
  419.     int    *kernMemSizePtr;
  420.     int    *numKernPagesPtr;
  421.     int    *maxSegsPtr;
  422.     int *maxProcessesPtr;
  423. {
  424.     register Address    virtAddr;
  425.     register int    i;
  426.     int            kernPages;
  427.     int            numPages;
  428. #ifdef sun4c
  429.     Mach_MemList    *memPtr;
  430.     int            nextVframeNum, numFrames;
  431. #endif
  432.  
  433. #if (MACH_MAX_NUM_PROCESSORS != 1) /* multiprocessor implementation */
  434.     Sync_SemInitDynamic(&vmMachMutex, "Vm:vmMachMutex");
  435. #endif
  436.  
  437. #ifdef sun4c
  438.     /*
  439.      * Initialize the physical to virtual page mappings, since memory isn't
  440.      * contiguous.
  441.      */
  442.     lastMemBoard = Mboards;
  443.     nextVframeNum = 0;
  444.     for (memPtr = *(romVectorPtr->availMemory); memPtr != (Mach_MemList *) 0;
  445.         memPtr = memPtr->next) {
  446.     if (memPtr->size != 0) {
  447.         numFrames = memPtr->size / VMMACH_PAGE_SIZE;
  448.         lastMemBoard->startVirPfNum = nextVframeNum;
  449.         lastMemBoard->endVirPfNum = nextVframeNum + numFrames;
  450.         nextVframeNum += numFrames;
  451.         lastMemBoard->physStartAddr = memPtr->address >> VMMACH_PAGE_SHIFT;
  452.         lastMemBoard->physEndAddr = lastMemBoard->physStartAddr + numFrames;
  453.         lastMemBoard++;
  454.     }
  455.     }
  456.     if (lastMemBoard == Mboards) {
  457.     panic("No memory boards in system configuration.");
  458.     }
  459. #endif
  460.     
  461.     kernPages = vmMachKernMemSize / VMMACH_PAGE_SIZE_INT;
  462.     /*
  463.      * Map all of the kernel memory that we might need one for one.  We know
  464.      * that the monitor maps the first part of memory one for one but for some
  465.      * reason it doesn't map enough.  We assume that the pmegs have been
  466.      * mapped correctly.
  467.      */
  468.     for (i = 0, virtAddr = (Address)mach_KernStart; 
  469.      i < kernPages;
  470.      i++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  471. #ifdef sun4
  472.         VmMachSetPageMap(virtAddr, 
  473.         (VmMachPTE)(VMMACH_KRW_PROT | VMMACH_RESIDENT_BIT |
  474.             VMMACH_DONT_CACHE_BIT | i));
  475. #else
  476.         VmMachSetPageMap(virtAddr, 
  477.         (VmMachPTE)(VMMACH_KRW_PROT | VMMACH_RESIDENT_BIT | i));
  478. #endif /* sun4 */
  479.     }
  480.  
  481.     /*
  482.      * Do boot time allocation.
  483.      */
  484.     sysMachPtr = (VmMach_SegData *)Vm_BootAlloc(sizeof(VmMach_SegData) + 
  485.         (sizeof (VMMACH_SEG_NUM) * VMMACH_NUM_SEGS_PER_CONTEXT));
  486.     numPages = GetNumPages();
  487.     refModMap = (VmMachPTE *)Vm_BootAlloc(sizeof(VmMachPTE) * numPages);
  488.  
  489.     /*
  490.      * Return lots of sizes to the machine independent module who called us.
  491.      */
  492.     *pageSizePtr = VMMACH_PAGE_SIZE;
  493.     *pageShiftPtr = VMMACH_PAGE_SHIFT;
  494.     *pageTableIncPtr = VMMACH_PAGE_TABLE_INCREMENT;
  495.     *kernMemSizePtr = vmMachKernMemSize;
  496.     *maxProcessesPtr = VMMACH_MAX_KERN_STACKS;
  497.     *numKernPagesPtr = GetNumPages();
  498.     /* 
  499.      * We don't care how many software segments there are so return -1 as
  500.      * the max.
  501.      */
  502.     *maxSegsPtr = -1;
  503. }
  504.  
  505.  
  506. /*
  507.  * ----------------------------------------------------------------------------
  508.  *
  509.  * GetNumPages --
  510.  *
  511.  *     Determine how many pages of physical memory there are.
  512.  *     For the sun4c, this determines how many physical pages of memory
  513.  *     are available after the prom has grabbed some.
  514.  *
  515.  * Results:
  516.  *     The number of physical pages available.
  517.  *
  518.  * Side effects:
  519.  *     None.
  520.  *
  521.  * ----------------------------------------------------------------------------
  522.  */
  523. static int
  524. GetNumPages()
  525. {
  526. #ifdef sun4c
  527.     int    memory = 0;
  528.     Mach_MemList    *memPtr;
  529.  
  530.     for (memPtr = *(romVectorPtr->availMemory); memPtr != (Mach_MemList *) 0;
  531.         memPtr = memPtr->next) {
  532.     memory += memPtr->size;
  533.     }
  534.     return (memory / VMMACH_PAGE_SIZE);
  535. #else
  536.     return (*romVectorPtr->memoryAvail / VMMACH_PAGE_SIZE);
  537. #endif
  538. }
  539.  
  540. #ifdef sun4c
  541.  
  542. /*
  543.  * ----------------------------------------------------------------------------
  544.  *
  545.  * VirtToPhysPage --
  546.  *
  547.  *     Translate from a virtual page to a physical page.
  548.  *     This was a macro on the other suns, but for the sun4c, physical
  549.  *     memory isn't contiguous.
  550.  *
  551.  * Results:
  552.  *     An address.
  553.  *
  554.  * Side effects:
  555.  *     None.
  556.  *
  557.  * ----------------------------------------------------------------------------
  558.  */
  559. static int
  560. VirtToPhysPage(pfNum)
  561.     int        pfNum;
  562. {
  563.     register    Memory_Board    *mb;
  564.  
  565.     for (mb = Mboards; mb < lastMemBoard; mb++) {
  566.     if (pfNum < mb->endVirPfNum) {
  567.         break;
  568.     }
  569.     }
  570.     return (mb->physStartAddr + pfNum - mb->startVirPfNum);
  571. }
  572.  
  573.  
  574. /*
  575.  * ----------------------------------------------------------------------------
  576.  *
  577.  * PhysToVirtPage --
  578.  *
  579.  *     Translate from a physical page to a virtual page.
  580.  *     This was a macro on the other suns, but for the sun4c, physical
  581.  *     memory isn't contiguous.
  582.  *
  583.  * Results:
  584.  *     An address.
  585.  *
  586.  * Side effects:
  587.  *     None.
  588.  *
  589.  * ----------------------------------------------------------------------------
  590.  */
  591. static int
  592. PhysToVirtPage(pfNum)
  593.     int        pfNum;
  594. {
  595.     register    Memory_Board    *mb;
  596.  
  597.     for (mb = Mboards; mb < lastMemBoard; mb++) {
  598.     if (pfNum >= mb->physStartAddr && pfNum < mb->physEndAddr) {
  599.         break;
  600.     }
  601.     }
  602.     return (pfNum - mb->physStartAddr + mb->startVirPfNum);
  603. }
  604. #endif /* sun4c */
  605.  
  606. #ifdef sun4c
  607.  
  608. /*
  609.  * ----------------------------------------------------------------------------
  610.  *
  611.  * VmMachSetSegMapInContext --
  612.  *
  613.  *    Set the segment map in a context that may not yet be mapped without
  614.  *    causing a fault.  So far, this is only useful on the sun4c.
  615.  *
  616.  * Results:
  617.  *     None.
  618.  *
  619.  * Side effects:
  620.  *     The segment map in another context is modified..
  621.  *
  622.  * ----------------------------------------------------------------------------
  623.  */
  624. static void
  625. VmMachSetSegMapInContext(context, addr, pmeg)
  626.     unsigned    int    context;
  627.     Address        addr;
  628.     unsigned    int    pmeg;
  629. {
  630.     romVectorPtr->SetSegInContext(context, addr, pmeg);
  631.     return;
  632. }
  633. #endif /* sun4c */
  634.  
  635.  
  636. /*
  637.  * ----------------------------------------------------------------------------
  638.  *
  639.  * VmMach_AllocKernSpace --
  640.  *
  641.  *     Allocate memory for machine dependent stuff in the kernels VAS.
  642.  *
  643.  * Results:
  644.  *     None.  Well, it returns something, Mike...  It seems to return the
  645.  *     address of the next free area.
  646.  *
  647.  * Side effects:
  648.  *     None.
  649.  *
  650.  * ----------------------------------------------------------------------------
  651.  */
  652. Address
  653. VmMach_AllocKernSpace(baseAddr)
  654.     Address    baseAddr;
  655. {
  656.     /*
  657.      * If the base address is at the beginning of a segment, we just want
  658.      * to allocate this segment for vmMachPTESegAddr.  If base addr is partway
  659.      * into a segment, we want a whole segment, so move to the next segment
  660.      * to allocate that one.  (baseAddr + VMMACH_SEG_SIZE - 1) moves us to
  661.      * next segment unless we were at the very beginning of one.  Then divide
  662.      * by VMMACH_SEG_SIZE to get segment number.  Then multiply by
  663.      * VMMACH_SEG_SIZE to get address of the begginning of the segment.
  664.      */
  665.     baseAddr = (Address) ((((unsigned int)baseAddr + VMMACH_SEG_SIZE - 1) / 
  666.                     VMMACH_SEG_SIZE) * VMMACH_SEG_SIZE);
  667.     vmMachPTESegAddr = baseAddr;    /* first seg for Pte mapping */
  668.     vmMachPMEGSegAddr = baseAddr + VMMACH_SEG_SIZE;    /* next for pmegs */
  669.     return(baseAddr + 2 * VMMACH_SEG_SIZE);    /* end of allocated area */
  670. }
  671.  
  672.  
  673. /*
  674.  * ----------------------------------------------------------------------------
  675.  *
  676.  * VmMach_Init --
  677.  *
  678.  *     Initialize all virtual memory data structures.
  679.  *
  680.  * Results:
  681.  *     None.
  682.  *
  683.  * Side effects:
  684.  *     All virtual memory linked lists and arrays are initialized.
  685.  *
  686.  * ----------------------------------------------------------------------------
  687.  */
  688. void
  689. VmMach_Init(firstFreePage)
  690.     int    firstFreePage;    /* Virtual page that is the first free for the 
  691.              * kernel. */
  692. {
  693. #ifndef sun4c
  694.     register     VMMACH_SEG_NUM    *segTablePtr;
  695. #endif sun4c
  696.     register     VmMachPTE    pte;
  697.     register    int         i;
  698.     int             firstFreeSegment;
  699.     Address            virtAddr;
  700.     Address            lastCodeAddr;
  701.     extern    int        etext;
  702. #ifdef sun4c
  703.     VMMACH_SEG_NUM        pmeg;
  704. #endif sun4c
  705.  
  706.     /*
  707.      * Initialize the kernel's hardware segment table.
  708.      */
  709.     vm_SysSegPtr->machPtr = sysMachPtr;
  710.     sysMachPtr->numSegs = VMMACH_NUM_SEGS_PER_CONTEXT;
  711.     sysMachPtr->offset = PageToSeg(vm_SysSegPtr->offset);
  712.     sysMachPtr->segTablePtr =
  713.         (VMMACH_SEG_NUM *) ((Address)sysMachPtr + sizeof(VmMach_SegData));
  714.     for (i = 0; i < VMMACH_NUM_SEGS_PER_CONTEXT; i++) {
  715.     sysMachPtr->segTablePtr[i] = VMMACH_INV_PMEG;
  716.     }
  717.  
  718.     /*
  719.      * Determine which hardware segment is the first that is not in use.
  720.      */
  721.     firstFreeSegment = ((firstFreePage - 1) << VMMACH_PAGE_SHIFT) / 
  722.                     VMMACH_SEG_SIZE + 1;
  723.     firstFreeSegment += (unsigned int)mach_KernStart >> VMMACH_SEG_SHIFT;
  724.  
  725.     /* 
  726.      * Initialize the PMEG and context tables and lists.
  727.      */
  728.     MMUInit(firstFreeSegment);
  729.  
  730.     /*
  731.      * Initialize the page map.
  732.      */
  733.     bzero((Address)refModMap, sizeof(VmMachPTE) * GetNumPages());
  734.  
  735.     /*
  736.      * The code segment is read only and all other in use kernel memory
  737.      * is read/write.  Since the loader may put the data in the same page
  738.      * as the last code page, the last code page is also read/write.
  739.      */
  740.     lastCodeAddr = (Address) ((unsigned)&etext - VMMACH_PAGE_SIZE);
  741.     for (i = 0, virtAddr = (Address)mach_KernStart;
  742.      i < firstFreePage;
  743.      virtAddr += VMMACH_PAGE_SIZE, i++) {
  744.     if (virtAddr >= (Address)MACH_CODE_START && 
  745.         virtAddr <= lastCodeAddr) {
  746.         pte = VMMACH_RESIDENT_BIT | VMMACH_KR_PROT | 
  747.               VirtToPhysPage(i) * VMMACH_CLUSTER_SIZE;
  748.     } else {
  749.         pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | 
  750.               VirtToPhysPage(i) * VMMACH_CLUSTER_SIZE;
  751. #ifdef sun4
  752.         if (virtAddr >= vmStackEndAddr) {
  753.         pte |= VMMACH_DONT_CACHE_BIT;
  754.         }
  755. #endif /* sun4 */
  756.         }
  757.     SET_ALL_PAGE_MAP(virtAddr, pte);
  758.     }
  759.  
  760.     /*
  761.      * Protect the bottom of the kernel stack.
  762.      */
  763.     SET_ALL_PAGE_MAP((Address)mach_StackBottom, (VmMachPTE)VirtToPhysPage(0));
  764.  
  765.     /*
  766.      * Invalid until the end of the last segment
  767.      */
  768.     for (;virtAddr < (Address) (firstFreeSegment << VMMACH_SEG_SHIFT);
  769.      virtAddr += VMMACH_PAGE_SIZE) {
  770.     SET_ALL_PAGE_MAP(virtAddr, (VmMachPTE)VirtToPhysPage(0));
  771.     }
  772.  
  773.     /* 
  774.      * Zero out the invalid pmeg.
  775.      */
  776.     /* Need I flush something? */
  777.     VmMachPMEGZero(VMMACH_INV_PMEG);
  778.  
  779.     /*
  780.      * Finally copy the kernel's context to each of the other contexts.
  781.      */
  782.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  783.     int        segNum;
  784.  
  785.     if (i == VMMACH_KERN_CONTEXT) {
  786.         continue;
  787.     }
  788. #ifndef sun4c
  789.     VmMachSetUserContext(i);
  790.     for (segNum = ((unsigned int) mach_KernStart) / VMMACH_SEG_SIZE,
  791.          segTablePtr = vm_SysSegPtr->machPtr->segTablePtr;
  792.          segNum < VMMACH_NUM_SEGS_PER_CONTEXT;
  793.          segNum++, segTablePtr++) {
  794.  
  795.         virtAddr = (Address) (segNum * VMMACH_SEG_SIZE);
  796.         /*
  797.          * No need to flush stuff since the other contexts haven't
  798.          * been used yet.
  799.          */
  800.         VmMachSetSegMap(virtAddr, (int)*segTablePtr);
  801.     }
  802. #else
  803.     /*
  804.      * For the sun4c, there is currently a problem just copying things
  805.      * out of the segTable, so do it from the real hardware.  I need to
  806.      * figure out what's wrong.
  807.      */
  808.     for (segNum = ((unsigned int) mach_KernStart) / VMMACH_SEG_SIZE;
  809.          segNum < VMMACH_NUM_SEGS_PER_CONTEXT; segNum++) {
  810.  
  811.         virtAddr = (Address) (segNum * VMMACH_SEG_SIZE);
  812.         if (virtAddr >= (Address) VMMACH_BOTTOM_OF_HOLE && 
  813.             virtAddr <= (Address) VMMACH_TOP_OF_HOLE) {
  814.         continue;
  815.         }
  816.         pmeg = VmMachGetSegMap(virtAddr);
  817.         VmMachSetSegMapInContext((unsigned char) i, virtAddr, pmeg);
  818.     }
  819. #endif
  820.     }
  821.     VmMachSetUserContext(VMMACH_KERN_CONTEXT);
  822.     if (Mach_GetMachineType() == SYS_SUN_3_50) {
  823.     unsigned int vidPage;
  824.  
  825. #define    VIDEO_START    0x100000    /* From Sun3 architecture manual */
  826. #define    VIDEO_SIZE    0x20000
  827.     vidPage = VIDEO_START / VMMACH_PAGE_SIZE;
  828.     if (firstFreePage > vidPage) {
  829.         panic("VmMach_Init: We overran video memory.\n");
  830.     }
  831.     /*
  832.      * On 3/50's the display is kept in main memory beginning at 1 
  833.      * Mbyte and going for 128 kbytes.  Reserve this memory so VM
  834.      * doesn't try to use it.
  835.      */
  836.     for (;vidPage < (VIDEO_START + VIDEO_SIZE) / VMMACH_PAGE_SIZE;
  837.          vidPage++) {
  838.         Vm_ReservePage(vidPage);
  839.     }
  840.     }
  841.     /*
  842.      * Turn on caching.
  843.      */
  844.     VmMachClearCacheTags();
  845. #ifndef sun4c
  846.     VmMachInitAddrErrorControlReg();
  847. #endif
  848.     VmMachInitSystemEnableReg();
  849. #ifdef NOTDEF
  850.     /*
  851.      * Initialize map of invalid pmegs for later copying.
  852.      */
  853.     for (i = 0; i < VMMACH_NUM_SEGS_PER_CONTEXT; i++) {
  854.     copyMap[i] = VMMACH_INV_PMEG;
  855.     }
  856. #endif NOTDEF
  857. #ifdef NOTDEF
  858. /* This is broken for now */
  859. #ifdef sun4c
  860.     MapColorMapAndIdRomAddr();
  861. #endif sun4c
  862. #endif NOTDEF
  863.  
  864. }
  865.  
  866.  
  867. /*
  868.  *----------------------------------------------------------------------
  869.  *
  870.  * MMUInit --
  871.  *
  872.  *    Initialize the context table and lists and the Pmeg table and 
  873.  *    lists.
  874.  *
  875.  * Results:
  876.  *    None.
  877.  *
  878.  * Side effects:
  879.  *    Context table and Pmeg table are initialized.  Also context list
  880.  *    and pmeg list are initialized.
  881.  *
  882.  *----------------------------------------------------------------------
  883.  */
  884. static void
  885. MMUInit(firstFreeSegment)
  886.     int        firstFreeSegment;
  887. {
  888.     register    int        i;
  889.     register    PMEG        *pmegPtr;
  890.     register    VMMACH_SEG_NUM    *segTablePtr;
  891.     VMMACH_SEG_NUM        pageCluster;
  892.  
  893.     /*
  894.      * Initialize the context table.
  895.      */
  896.     contextArray[VMMACH_KERN_CONTEXT].flags = CONTEXT_IN_USE;
  897.     List_Init(contextList);
  898.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  899.     if (i != VMMACH_KERN_CONTEXT) {
  900.         contextArray[i].flags = 0;
  901.         List_Insert((List_Links *) &contextArray[i], 
  902.             LIST_ATREAR(contextList));
  903.     }
  904.     contextArray[i].context = i;
  905.     }
  906.  
  907.     /*
  908.      * Initialize the page cluster list.
  909.      */
  910.     List_Init(pmegFreeList);
  911.     List_Init(pmegInuseList);
  912.  
  913.     /*
  914.      * Initialize the pmeg structure.
  915.      */
  916.     bzero((Address)pmegArray, VMMACH_NUM_PMEGS * sizeof(PMEG));
  917.     for (i = 0, pmegPtr = pmegArray; i < VMMACH_NUM_PMEGS; i++, pmegPtr++) {
  918.     pmegPtr->segInfo.segPtr = (Vm_Segment *) NIL;
  919.     pmegPtr->flags = PMEG_DONT_ALLOC;
  920.     pmegPtr->segInfo.nextLink = (struct PMEGseg *)NIL;
  921.     }
  922.  
  923. #ifdef sun2
  924.     /*
  925.      * Segment 0 is left alone because it is required for the monitor.
  926.      */
  927.     pmegArray[0].segPtr = (Vm_Segment *)NIL;
  928.     pmegArray[0].hardSegNum = 0;
  929.     i = 1;
  930. #else
  931.     i = 0;
  932. #endif /* sun2 */
  933.  
  934.     /*
  935.      * Invalidate all hardware segments from first segment up to the beginning
  936.      * of the kernel.
  937.      */
  938.     for (; i < ((((unsigned int) mach_KernStart) & VMMACH_ADDR_MASK) >>
  939.         VMMACH_SEG_SHIFT); i++) {
  940.     int    j;
  941.  
  942.     /*
  943.      * Copy the invalidation to all the other contexts, so that
  944.      * the user contexts won't have double-mapped pmegs at the low-address
  945.      * segments.
  946.      */
  947.     for (j = 0; j < VMMACH_NUM_CONTEXTS; j++) {
  948.         Address    addr;
  949.  
  950. #ifndef sun4c
  951.         VmMachSetUserContext(j);
  952. #endif
  953.         addr = (Address) (i << VMMACH_SEG_SHIFT);
  954.         /* Yes, do this here since user stuff would be double mapped. */
  955. #ifndef sun4c
  956.         VmMachSetSegMap(addr, VMMACH_INV_PMEG);
  957. #else
  958.         VmMachSetSegMapInContext((unsigned char) j, addr,
  959.             (unsigned char) VMMACH_INV_PMEG);
  960. #endif
  961.     }
  962.     }
  963.     VmMachSetUserContext(VMMACH_KERN_CONTEXT);
  964.     i = ((unsigned int) mach_KernStart >> VMMACH_SEG_SHIFT);
  965.  
  966.     /*
  967.      * Reserve all pmegs that have kernel code or heap.
  968.      */
  969.     for (segTablePtr = vm_SysSegPtr->machPtr->segTablePtr;
  970.          i < firstFreeSegment;
  971.      i++, segTablePtr++) {
  972.     pageCluster = VmMachGetSegMap((Address) (i << VMMACH_SEG_SHIFT));
  973.     pmegArray[pageCluster].pageCount = VMMACH_NUM_PAGES_PER_SEG;
  974.     pmegArray[pageCluster].segInfo.segPtr = vm_SysSegPtr;
  975.     pmegArray[pageCluster].segInfo.hardSegNum = i;
  976.     *segTablePtr = pageCluster;
  977.     }
  978.  
  979.     /*
  980.      * Invalidate all hardware segments that aren't in code or heap and are 
  981.      * before the specially mapped page clusters.
  982.      */
  983.     for (; i < VMMACH_FIRST_SPECIAL_SEG; i++, segTablePtr++) {
  984.     Address    addr;
  985.     /* Yes, do this here, since user stuff would be double-mapped. */
  986.     addr = (Address) (i << VMMACH_SEG_SHIFT);
  987.     VmMachSetSegMap(addr, VMMACH_INV_PMEG);
  988.     }
  989.  
  990.     /*
  991.      * Mark the invalid pmeg so that it never gets used.
  992.      */
  993.     pmegArray[VMMACH_INV_PMEG].segInfo.segPtr = vm_SysSegPtr;
  994.     pmegArray[VMMACH_INV_PMEG].flags = PMEG_NEVER_FREE;
  995.  
  996.     /*
  997.      * Now reserve the rest of the page clusters that have been set up by
  998.      * the monitor.  Don't reserve any PMEGs that don't have any valid 
  999.      * mappings in them.
  1000.      */
  1001.     for (; i < VMMACH_NUM_SEGS_PER_CONTEXT; i++, segTablePtr++) {
  1002.     Address        virtAddr;
  1003.     int        j;
  1004.     VmMachPTE    pte;
  1005.     Boolean        inusePMEG;
  1006.  
  1007.     virtAddr = (Address) (i << VMMACH_SEG_SHIFT);
  1008.         if ((virtAddr >= (Address)VMMACH_DMA_START_ADDR) &&
  1009.         (virtAddr < (Address)(VMMACH_DMA_START_ADDR+VMMACH_DMA_SIZE))) {
  1010.         /*
  1011.          * Blow away anything in DMA space. 
  1012.          */
  1013.         pageCluster = VMMACH_INV_PMEG;
  1014.         VmMachSetSegMap(virtAddr, VMMACH_INV_PMEG);
  1015.     } else {
  1016.         pageCluster = VmMachGetSegMap(virtAddr);
  1017.         if (pageCluster != VMMACH_INV_PMEG) {
  1018.         inusePMEG = FALSE;
  1019.         for (j = 0; 
  1020.              j < VMMACH_NUM_PAGES_PER_SEG_INT; 
  1021.              j++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  1022.             pte = VmMachGetPageMap(virtAddr);
  1023.             if ((pte & VMMACH_RESIDENT_BIT) &&
  1024.             (pte & (VMMACH_TYPE_FIELD|VMMACH_PAGE_FRAME_FIELD)) != 0) {
  1025.             /*
  1026.              * A PMEG contains a valid mapping if the resident
  1027.              * bit is set and the page frame and type field
  1028.              * are non-zero.  On Sun 2/50's the PROM sets
  1029.              * the resident bit but leaves the page frame equal
  1030.              * to zero.
  1031.              */
  1032.             if (!inusePMEG) {
  1033.                 pmegArray[pageCluster].segInfo.segPtr =
  1034.                     vm_SysSegPtr;
  1035.                 pmegArray[pageCluster].segInfo.hardSegNum = i;
  1036.                 pmegArray[pageCluster].flags = PMEG_NEVER_FREE;
  1037.                 inusePMEG = TRUE;
  1038.             }
  1039.             } else {
  1040.             VmMachSetPageMap(virtAddr, (VmMachPTE)0);
  1041.             }
  1042.         }
  1043.         virtAddr -= VMMACH_SEG_SIZE;
  1044.         if (!inusePMEG ||
  1045.             (virtAddr >= (Address)VMMACH_DMA_START_ADDR &&
  1046.              virtAddr < (Address)(VMMACH_DMA_START_ADDR+VMMACH_DMA_SIZE))) {
  1047. #ifdef PRINT_ZAP
  1048.             int z;
  1049.             /* 
  1050.              * We didn't find any valid mappings in the PMEG or the PMEG
  1051.              * is in DMA space so delete it.
  1052.              */
  1053.             printf("Zapping segment at virtAddr %x\n", virtAddr);
  1054.             for (z = 0; z < 100000; z++) {
  1055.             }
  1056. #endif
  1057.             VmMachSetSegMap(virtAddr, VMMACH_INV_PMEG);
  1058.             pageCluster = VMMACH_INV_PMEG;
  1059.         }
  1060.         }
  1061.     }
  1062.     *segTablePtr = pageCluster;
  1063.     }
  1064.  
  1065. #if defined (sun3)
  1066.     /*
  1067.      * We can't use the hardware segment that corresponds to the
  1068.      * last segment of physical memory for some reason.  Zero it out
  1069.      * and can't reboot w/o powering the machine off.
  1070.      */
  1071.     dontUse = (*romVectorPtr->memoryAvail - 1) / VMMACH_SEG_SIZE;
  1072. #endif
  1073.  
  1074.     /*
  1075.      * Now finally, all page clusters that have a NIL segment pointer are
  1076.      * put onto the page cluster fifo.  On a Sun-3 one hardware segment is 
  1077.      * off limits for some reason.  Zero it out and can't reboot w/o 
  1078.      * powering the machine off.
  1079.      */
  1080.     for (i = 0, pmegPtr = pmegArray; i < VMMACH_NUM_PMEGS; i++, pmegPtr++) {
  1081.  
  1082.     if (pmegPtr->segInfo.segPtr == (Vm_Segment *) NIL 
  1083. #if defined (sun3)
  1084.         && i != dontUse
  1085. #endif
  1086.     ) {
  1087.         List_Insert((List_Links *) pmegPtr, LIST_ATREAR(pmegFreeList));
  1088.         pmegPtr->flags = 0;
  1089.         VmMachPMEGZero(i);
  1090.     }
  1091.     }
  1092. }
  1093.  
  1094. #ifdef NOTDEF
  1095. /* This is broken for now */
  1096. #ifdef sun4c
  1097. static char    colorArray[3 * 0x1000];
  1098. #ifdef ID
  1099. static char    idArray[2 * 0x1000];
  1100. #endif ID
  1101.  
  1102. /*
  1103.  * ----------------------------------------------------------------------------
  1104.  *
  1105.  * MapColorMapAndIdRomAddr --
  1106.  *
  1107.  *      Get the physical address of the color map for a sparc station and map
  1108.  *    it to a virtual address.  Also map the id words for the video
  1109.  *    subsystem.
  1110.  *
  1111.  * Results:
  1112.  *      None.
  1113.  *
  1114.  * Side effects:
  1115.  *      Page maps are altered.  Several pages of physical memory are wasted.
  1116.  *
  1117.  * ----------------------------------------------------------------------------
  1118.  */
  1119. static void
  1120. MapColorMapAndIdRomAddr()
  1121. {
  1122.     VmMachPTE        colorPte;
  1123.     VmMachPTE        idPte;
  1124.     unsigned int    otherbits;
  1125.     Address        colorVirtAddr;
  1126.     Address        idVirtAddr;
  1127.  
  1128.     colorPte = VmMachGetPageMap(DEV_FRAME_BUF_ADDR);
  1129.     otherbits = colorPte &(~VMMACH_PAGE_FRAME_FIELD);
  1130.     colorPte &= VMMACH_PAGE_FRAME_FIELD;
  1131.     if ((colorPte & 0xfff) != 0x800) {
  1132.     panic("MapColorMapAndIdRomAddr: frame buffer addr is weird: 0x%x\n",
  1133.         colorPte);
  1134.     }
  1135.     /* Change last bits to color map offset and id rom offset */
  1136.     colorPte &= 0xfffff000;
  1137. #ifdef ID
  1138.     idPte = colorPte;
  1139. #endif
  1140.     colorPte |= 0x400;
  1141.     colorPte |= otherbits;
  1142. #ifdef ID
  1143.     idPte |= otherbits;        /* 0 offset */
  1144. #endif
  1145.  
  1146.     /* allocate 2 pages on a page boundary */
  1147. #ifdef NOTDEF
  1148.     colorVirtAddr = (Address) malloc(3 * 0x1000);
  1149. #else
  1150.     colorVirtAddr = colorArray;
  1151. #endif
  1152.     ((unsigned int)colorVirtAddr) &= 0xfffff000;
  1153.  
  1154.     /* and another 2 pages */
  1155. #ifdef NOTDEF
  1156.     idVirtAddr = (Address) malloc(3 * 0x1000);
  1157. #else NOTDEF
  1158. #ifdef ID
  1159.     idVirtAddr = idArray;
  1160. #endif ID
  1161. #endif NOTDEF
  1162. #ifdef ID
  1163.     ((unsigned int)idVirtAddr) &= 0xfffff000;
  1164. #endif
  1165.  
  1166.     /* This wastes 3 pages of physical memory.  That's a shame. */
  1167.     VmMachSetPageMap(colorVirtAddr, colorPte);
  1168.     VmMachSetPageMap(colorVirtAddr + 0x1000, colorPte + 1);
  1169.  
  1170. #ifdef ID
  1171.     /* This wastes 3 pages of physical memory again. */
  1172.     VmMachSetPageMap(idVirtAddr, idPte);
  1173.     VmMachSetPageMap(idVirtAddr + 0x1000, idPte + 1);
  1174.     printf("colorPte 0x%x, idPte 0x%x, colorVA 0x%x, idVA 0x%x\n",
  1175.     colorPte, idPte, colorVirtAddr, idVirtAddr);
  1176. #else
  1177.     printf("colorPte 0x%x, colorVA 0x%x\n",
  1178.     colorPte, colorVirtAddr);
  1179. #endif
  1180.  
  1181.     return;
  1182. }
  1183. #endif sun4c
  1184. #endif NOTDEF
  1185.  
  1186.  
  1187.  
  1188. /*
  1189.  * ----------------------------------------------------------------------------
  1190.  *
  1191.  * VmMach_SegInit --
  1192.  *
  1193.  *      Initialize hardware dependent data for a segment.
  1194.  *
  1195.  * Results:
  1196.  *      None.
  1197.  *
  1198.  * Side effects:
  1199.  *      Machine dependent data struct and is allocated and initialized.
  1200.  *
  1201.  * ----------------------------------------------------------------------------
  1202.  */
  1203. void
  1204. VmMach_SegInit(segPtr)
  1205.     Vm_Segment    *segPtr;
  1206. {
  1207.     register    VmMach_SegData    *segDataPtr;
  1208.     int                segTableSize;
  1209.     int        i;
  1210.  
  1211.     if (segPtr->type == VM_CODE) {
  1212.     segTableSize =
  1213.         (segPtr->ptSize + segPtr->offset + VMMACH_NUM_PAGES_PER_SEG - 1) / 
  1214.                             VMMACH_NUM_PAGES_PER_SEG;
  1215.     } else {
  1216.     segTableSize = segPtr->ptSize / VMMACH_NUM_PAGES_PER_SEG;
  1217.     }
  1218.     segDataPtr = (VmMach_SegData *)malloc(sizeof(VmMach_SegData) +
  1219.     (segTableSize * sizeof (VMMACH_SEG_NUM)));
  1220.  
  1221.     segDataPtr->numSegs = segTableSize;
  1222.     segDataPtr->offset = PageToSeg(segPtr->offset);
  1223.     segDataPtr->segTablePtr =
  1224.         (VMMACH_SEG_NUM *) ((Address)segDataPtr + sizeof(VmMach_SegData));
  1225.     for (i = 0; i < segTableSize; i++) {
  1226.     segDataPtr->segTablePtr[i] = VMMACH_INV_PMEG;
  1227.     }
  1228.     segPtr->machPtr = segDataPtr;
  1229.     /*
  1230.      * Set the minimum and maximum virtual addresses for this segment to
  1231.      * be as small and as big as possible respectively because things will
  1232.      * be prevented from growing automatically as soon as segments run into
  1233.      * each other.
  1234.      */
  1235.     segPtr->minAddr = (Address)0;
  1236.     segPtr->maxAddr = (Address)0xffffffff;
  1237. }
  1238.  
  1239.  
  1240. /*
  1241.  *----------------------------------------------------------------------
  1242.  *
  1243.  * VmMach_SegExpand --
  1244.  *
  1245.  *    Allocate more space for the machine dependent structure.
  1246.  *
  1247.  * Results:
  1248.  *    None.
  1249.  *
  1250.  * Side effects:
  1251.  *    Memory allocated for a new hardware segment table.
  1252.  *
  1253.  *----------------------------------------------------------------------
  1254.  */
  1255. /*ARGSUSED*/
  1256. void
  1257. VmMach_SegExpand(segPtr, firstPage, lastPage)
  1258.     register    Vm_Segment    *segPtr;    /* Segment to expand. */
  1259.     int                firstPage;    /* First page to add. */
  1260.     int                lastPage;    /* Last page to add. */
  1261. {
  1262.     int                newSegTableSize;
  1263.     register    VmMach_SegData    *oldSegDataPtr;
  1264.     register    VmMach_SegData    *newSegDataPtr;
  1265.  
  1266.     newSegTableSize = segPtr->ptSize / VMMACH_NUM_PAGES_PER_SEG;
  1267.     oldSegDataPtr = segPtr->machPtr;
  1268.     if (newSegTableSize <= oldSegDataPtr->numSegs) {
  1269.     return;
  1270.     }
  1271.     newSegDataPtr = 
  1272.     (VmMach_SegData *)malloc(sizeof(VmMach_SegData) + (newSegTableSize *
  1273.         sizeof (VMMACH_SEG_NUM)));
  1274.     newSegDataPtr->numSegs = newSegTableSize;
  1275.     newSegDataPtr->offset = PageToSeg(segPtr->offset);
  1276.     newSegDataPtr->segTablePtr = (VMMACH_SEG_NUM *) ((Address)newSegDataPtr +
  1277.             sizeof(VmMach_SegData));
  1278.     CopySegData(segPtr, oldSegDataPtr, newSegDataPtr);
  1279.     free((Address)oldSegDataPtr);
  1280. }
  1281.  
  1282.  
  1283. /*
  1284.  *----------------------------------------------------------------------
  1285.  *
  1286.  * CopySegData --
  1287.  *
  1288.  *    Copy over the old hardware segment data into the new expanded
  1289.  *    structure.
  1290.  *
  1291.  * Results:
  1292.  *    None.
  1293.  *
  1294.  * Side effects:
  1295.  *    The hardware segment table is copied.
  1296.  *
  1297.  *----------------------------------------------------------------------
  1298.  */
  1299. ENTRY static void
  1300. CopySegData(segPtr, oldSegDataPtr, newSegDataPtr)
  1301.     register    Vm_Segment    *segPtr;    /* The segment to add the
  1302.                            virtual pages to. */
  1303.     register    VmMach_SegData    *oldSegDataPtr;
  1304.     register    VmMach_SegData    *newSegDataPtr;
  1305. {
  1306.     int        i, j;
  1307.  
  1308.     MASTER_LOCK(vmMachMutexPtr);
  1309.  
  1310.     if (segPtr->type == VM_HEAP) {
  1311.     /*
  1312.      * Copy over the hardware segment table into the lower part
  1313.      * and set the rest to invalid.
  1314.      */
  1315.     bcopy((Address)oldSegDataPtr->segTablePtr,
  1316.         (Address)newSegDataPtr->segTablePtr,
  1317.         oldSegDataPtr->numSegs * sizeof (VMMACH_SEG_NUM));
  1318.     j = newSegDataPtr->numSegs - oldSegDataPtr->numSegs;
  1319.  
  1320.     for (i = 0; i < j; i++) {
  1321.         newSegDataPtr->segTablePtr[oldSegDataPtr->numSegs + i]
  1322.             = VMMACH_INV_PMEG;
  1323.     }
  1324.     } else {
  1325.     /*
  1326.      * Copy the current segment table into the high part of the
  1327.      * new segment table and set the lower part to invalid.
  1328.      */
  1329.     bcopy((Address)oldSegDataPtr->segTablePtr,
  1330.         (Address)(newSegDataPtr->segTablePtr + 
  1331.         newSegDataPtr->numSegs - oldSegDataPtr->numSegs),
  1332.         oldSegDataPtr->numSegs * sizeof (VMMACH_SEG_NUM));
  1333.     j = newSegDataPtr->numSegs - oldSegDataPtr->numSegs;
  1334.  
  1335.     for (i = 0; i < j; i++) {
  1336.         newSegDataPtr->segTablePtr[i] = VMMACH_INV_PMEG;
  1337.     }
  1338.     }
  1339.     segPtr->machPtr = newSegDataPtr;
  1340.  
  1341.     MASTER_UNLOCK(vmMachMutexPtr);
  1342. }
  1343.  
  1344.  
  1345. /*
  1346.  * ----------------------------------------------------------------------------
  1347.  *
  1348.  * VmMach_SegDelete --
  1349.  *
  1350.  *      Free hardware dependent resources for this software segment.
  1351.  *
  1352.  * Results:
  1353.  *      None.
  1354.  *
  1355.  * Side effects:
  1356.  *      Machine dependent struct freed and the pointer in the segment
  1357.  *    is set to NIL.
  1358.  *
  1359.  * ----------------------------------------------------------------------------
  1360.  */
  1361. void
  1362. VmMach_SegDelete(segPtr)
  1363.     register    Vm_Segment    *segPtr;    /* Pointer to segment to free. */
  1364. {
  1365.     if (vm_Tracing) {
  1366.     Vm_TraceSegDestroy    segDestroy;
  1367.  
  1368.     segDestroy.segNum = segPtr->segNum;
  1369.     VmStoreTraceRec(VM_TRACE_SEG_DESTROY_REC, sizeof(segDestroy),
  1370.             (Address)&segDestroy, TRUE);
  1371.     }
  1372.  
  1373.     SegDelete(segPtr);
  1374.     free((Address)segPtr->machPtr);
  1375.     segPtr->machPtr = (VmMach_SegData *)NIL;
  1376.     if (segPtr->type==VM_SHARED && debugVmStubs) {
  1377.     printf("Done with seg %d\n", segPtr->segNum);
  1378.     }
  1379. }
  1380.  
  1381.  
  1382. /*
  1383.  * ----------------------------------------------------------------------------
  1384.  *
  1385.  * SegDelete --
  1386.  *
  1387.  *      Free up any pmegs used by this segment.
  1388.  *
  1389.  * Results:
  1390.  *      None.
  1391.  *
  1392.  * Side effects:
  1393.  *      All pmegs used by this segment are freed.
  1394.  *
  1395.  * ----------------------------------------------------------------------------
  1396.  */
  1397. ENTRY static void
  1398. SegDelete(segPtr)
  1399.     Vm_Segment    *segPtr;    /* Pointer to segment to free. */
  1400. {
  1401.     register    int         i;
  1402.     register    VMMACH_SEG_NUM    *pmegPtr;
  1403.     register    VmMach_SegData    *machPtr;
  1404.  
  1405.     MASTER_LOCK(vmMachMutexPtr);
  1406.  
  1407.     machPtr = segPtr->machPtr;
  1408.     for (i = 0, pmegPtr = (VMMACH_SEG_NUM *) machPtr->segTablePtr;
  1409.          i < machPtr->numSegs; i++, pmegPtr++) {
  1410.     if (*pmegPtr != VMMACH_INV_PMEG) {
  1411.         /* Flushing is done in PMEGFree */
  1412.         PMEGFree((int) *pmegPtr);
  1413.     }
  1414.     }
  1415.  
  1416.     MASTER_UNLOCK(vmMachMutexPtr);
  1417. }
  1418.  
  1419.  
  1420. /*
  1421.  *----------------------------------------------------------------------
  1422.  *
  1423.  * VmMach_GetContext --
  1424.  *
  1425.  *    Return the context for a process, given its pcb.
  1426.  *
  1427.  * Results:
  1428.  *    Context number for process. -1 if the process doesn't
  1429.  *    have a context allocated.
  1430.  *
  1431.  * Side effects:
  1432.  *    None.
  1433.  *
  1434.  *----------------------------------------------------------------------
  1435.  */
  1436. int
  1437. VmMach_GetContext(procPtr)
  1438.     Proc_ControlBlock    *procPtr;
  1439. {
  1440.     VmMach_Context    *contextPtr;
  1441.     contextPtr = procPtr->vmPtr->machPtr->contextPtr;
  1442.     return ((contextPtr == (VmMach_Context *)NIL) ? -1 : contextPtr->context);
  1443. }
  1444.  
  1445.  
  1446. /*
  1447.  *----------------------------------------------------------------------
  1448.  *
  1449.  * VmMach_ProcInit --
  1450.  *
  1451.  *    Initalize the machine dependent part of the VM proc info.
  1452.  *
  1453.  * Results:
  1454.  *    None.
  1455.  *
  1456.  * Side effects:
  1457.  *    Machine dependent proc info is initialized.
  1458.  *
  1459.  *----------------------------------------------------------------------
  1460.  */
  1461. void
  1462. VmMach_ProcInit(vmPtr)
  1463.     register    Vm_ProcInfo    *vmPtr;
  1464. {
  1465.     if (vmPtr->machPtr == (VmMach_ProcData *)NIL) {
  1466.     vmPtr->machPtr = (VmMach_ProcData *)malloc(sizeof(VmMach_ProcData));
  1467.     }
  1468.     vmPtr->machPtr->contextPtr = (VmMach_Context *)NIL;
  1469.     vmPtr->machPtr->mapSegPtr = (struct Vm_Segment *)NIL;
  1470.     vmPtr->machPtr->sharedData.allocVector = (int *)NIL;
  1471. }
  1472.  
  1473.  
  1474. /*
  1475.  * ----------------------------------------------------------------------------
  1476.  *
  1477.  * PMEGGet --
  1478.  *
  1479.  *      Return the next pmeg from the list of available pmegs.  If the 
  1480.  *      lock flag is set then the pmeg is removed from the pmeg list.
  1481.  *      Otherwise it is moved to the back.
  1482.  *
  1483.  * Results:
  1484.  *      The pmeg number that is allocated.
  1485.  *
  1486.  * Side effects:
  1487.  *      A pmeg is either removed from the pmeg list or moved to the back.
  1488.  *
  1489.  * ----------------------------------------------------------------------------
  1490.  */
  1491. INTERNAL static int
  1492. PMEGGet(softSegPtr, hardSegNum, flags)
  1493.     Vm_Segment     *softSegPtr;    /* Which software segment this is. */
  1494.     int        hardSegNum;    /* Which hardware segment in the software 
  1495.                    segment that this is */
  1496.     Boolean    flags;        /* Flags that indicate the state of the pmeg. */
  1497. {
  1498.     register PMEG        *pmegPtr;
  1499.     register Vm_Segment        *segPtr;
  1500.     register VmMachPTE        *ptePtr;
  1501.     register VmMach_Context    *contextPtr;
  1502.     register int        i;
  1503.     register VmMachPTE        hardPTE;
  1504.     VmMachPTE            pteArray[VMMACH_NUM_PAGES_PER_SEG_INT];
  1505.     int                     oldContext;
  1506.     int                pmegNum;
  1507.     Address            virtAddr;
  1508.     Boolean            found = FALSE;
  1509.     int                numValidPages;
  1510.     struct PMEGseg        *curSeg, *nextSeg;
  1511.  
  1512.     if (List_IsEmpty(pmegFreeList)) {
  1513.     
  1514.     LIST_FORALL(pmegInuseList, (List_Links *)pmegPtr) {
  1515.         if (pmegPtr->lockCount == 0) {
  1516.         found = TRUE;
  1517.         break;
  1518.         }
  1519.     }
  1520.     if (!found) {
  1521.         panic("Pmeg lists empty\n");
  1522.         return(VMMACH_INV_PMEG);
  1523.     }
  1524.     } else {
  1525.     pmegPtr = (PMEG *)List_First(pmegFreeList);
  1526.     }
  1527.     pmegNum = pmegPtr - pmegArray;
  1528.  
  1529.     oldContext = VmMachGetContextReg();
  1530.     if (pmegPtr->segInfo.segPtr != (Vm_Segment *) NIL) {
  1531.     /*
  1532.      * Need to steal the pmeg from its current owner.
  1533.      */
  1534.     for (curSeg = &pmegPtr->segInfo; curSeg != (struct PMEGseg *)NIL;) {
  1535.         vmStat.machDepStat.stealPmeg++;
  1536.         segPtr = curSeg->segPtr;
  1537.         *GetHardSegPtr(segPtr->machPtr, curSeg->hardSegNum) =
  1538.             VMMACH_INV_PMEG;
  1539.         virtAddr = (Address) (curSeg->hardSegNum << VMMACH_SEG_SHIFT);
  1540.         /*
  1541.          * Delete the pmeg from all appropriate contexts.
  1542.          */
  1543.         if (segPtr->type == VM_SYSTEM) {
  1544.         /*
  1545.          * For cache accesses of data with the supervisor tag set,
  1546.          * the flush only needs to be done in one context.
  1547.          */
  1548.         numValidPages = GetNumValidPages(virtAddr);
  1549.         if (numValidPages >
  1550.             (VMMACH_CACHE_SIZE / VMMACH_PAGE_SIZE_INT)) {
  1551.             VmMachFlushSegment(virtAddr);
  1552.         } else {
  1553.             /* flush the pages */
  1554.             FlushValidPages(virtAddr);
  1555.         }
  1556.  
  1557.         for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  1558.             VmMachSetContextReg(i);
  1559.             VmMachSetSegMap(virtAddr, VMMACH_INV_PMEG);
  1560.         }
  1561.         } else {
  1562.         for (i = 1, contextPtr = &contextArray[1];
  1563.              i < VMMACH_NUM_CONTEXTS; 
  1564.              i++, contextPtr++) {
  1565.             if (contextPtr->flags & CONTEXT_IN_USE) {
  1566.             if (contextPtr->map[curSeg->hardSegNum] ==
  1567.                 pmegNum) {
  1568.                 VmMachSetContextReg(i);
  1569.                 contextPtr->map[curSeg->hardSegNum] =
  1570.                     VMMACH_INV_PMEG;
  1571.                 numValidPages = GetNumValidPages(virtAddr);
  1572.                 if (numValidPages >
  1573.                     (VMMACH_CACHE_SIZE / VMMACH_PAGE_SIZE_INT)) {
  1574.                 VmMachFlushSegment(virtAddr);
  1575.                 } else {
  1576.                 /* flush the pages */
  1577.                 FlushValidPages(virtAddr);
  1578.                 }
  1579.                 VmMachSetSegMap(virtAddr, VMMACH_INV_PMEG);
  1580.             }
  1581.             if (contextPtr->map[MAP_SEG_NUM] == pmegNum) {
  1582.                 VmMachSetContextReg(i);
  1583.                 contextPtr->map[MAP_SEG_NUM] = VMMACH_INV_PMEG;
  1584.                 VmMachFlushSegment((Address)VMMACH_MAP_SEG_ADDR);
  1585.                 VmMachSetSegMap((Address)VMMACH_MAP_SEG_ADDR,
  1586.                         VMMACH_INV_PMEG);
  1587.             }
  1588.             }
  1589.         }
  1590.         }
  1591.         nextSeg = curSeg->nextLink;
  1592.         if (curSeg != &pmegPtr->segInfo) {
  1593.         free((char *)curSeg);
  1594.         }
  1595.         curSeg = nextSeg;
  1596.     }
  1597.     pmegPtr->segInfo.nextLink = (struct PMEGseg *)NIL;
  1598.     VmMachSetContextReg(oldContext);
  1599.     /*
  1600.      * Read out all reference and modify bits from the pmeg.
  1601.      */
  1602.     if (pmegPtr->pageCount > 0) {
  1603.         Boolean    printedStealPMEG = FALSE;
  1604.  
  1605.         ptePtr = pteArray;
  1606.         VmMachReadAndZeroPMEG(pmegNum, ptePtr);
  1607.         for (i = 0;
  1608.          i < VMMACH_NUM_PAGES_PER_SEG_INT;
  1609.          i++, ptePtr++) {
  1610.         hardPTE = *ptePtr;
  1611.         if ((hardPTE & VMMACH_RESIDENT_BIT) &&
  1612.             (hardPTE & (VMMACH_REFERENCED_BIT | VMMACH_MODIFIED_BIT))) {
  1613.             if (vm_Tracing) {
  1614.             if (!printedStealPMEG) {
  1615.                 short    stealPMEGRec;
  1616.  
  1617.                 printedStealPMEG = TRUE;
  1618.                 printedSegTrace = FALSE;
  1619.                 tracePMEGPtr = pmegPtr;
  1620.                 VmStoreTraceRec(VM_TRACE_STEAL_PMEG_REC,
  1621.                         sizeof(short), 
  1622.                         (Address)&stealPMEGRec,TRUE);
  1623.             }
  1624.             VmMachTracePage(hardPTE,
  1625.                 (unsigned int) (VMMACH_NUM_PAGES_PER_SEG_INT - i));
  1626.             } else {
  1627.             refModMap[PhysToVirtPage(hardPTE & VMMACH_PAGE_FRAME_FIELD)]
  1628.              |= hardPTE & (VMMACH_REFERENCED_BIT | VMMACH_MODIFIED_BIT);
  1629.             }
  1630.         }
  1631.         }
  1632.     }
  1633.     }
  1634.  
  1635.     /* Initialize the pmeg and delete it from the fifo.  If we aren't 
  1636.      * supposed to lock this pmeg, then put it at the rear of the list.
  1637.      */
  1638.     pmegPtr->segInfo.segPtr = softSegPtr;
  1639.     pmegPtr->segInfo.hardSegNum = hardSegNum;
  1640.     pmegPtr->pageCount = 0;
  1641.     List_Remove((List_Links *) pmegPtr);
  1642.     if (!(flags & PMEG_DONT_ALLOC)) {
  1643.     List_Insert((List_Links *) pmegPtr, LIST_ATREAR(pmegInuseList));
  1644.     }
  1645.     pmegPtr->flags = flags;
  1646.  
  1647.     return(pmegNum);
  1648. }
  1649.  
  1650.  
  1651. /*
  1652.  *----------------------------------------------------------------------
  1653.  *
  1654.  * GetNumValidPages --
  1655.  *
  1656.  *    Return the number of valid pages in a segment.
  1657.  *
  1658.  * Results:
  1659.  *    The number of valid pages.
  1660.  *
  1661.  * Side effects:
  1662.  *    None.
  1663.  *
  1664.  *----------------------------------------------------------------------
  1665.  */
  1666. static int
  1667. GetNumValidPages(virtAddr)
  1668.     Address    virtAddr;
  1669. {
  1670.     int        i;
  1671.     int        numValid = 0;
  1672.     unsigned    int    pte;
  1673.  
  1674.     for (i = 0; i < (VMMACH_SEG_SIZE / VMMACH_PAGE_SIZE_INT); i++) {
  1675.     pte = VmMachGetPageMap(virtAddr + (i * VMMACH_PAGE_SIZE_INT));
  1676.     if (pte & VMMACH_RESIDENT_BIT) {
  1677.         numValid++;
  1678.     }
  1679.     }
  1680.  
  1681.     return numValid;
  1682. }
  1683.  
  1684.  
  1685. /*
  1686.  *----------------------------------------------------------------------
  1687.  *
  1688.  * FlushValidPages --
  1689.  *
  1690.  *    Flush the valid pages in a segment.
  1691.  *
  1692.  * Results:
  1693.  *    None.
  1694.  *
  1695.  * Side effects:
  1696.  *    The valid pages in a segment are flushed.
  1697.  *
  1698.  *----------------------------------------------------------------------
  1699.  */
  1700. static void
  1701. FlushValidPages(virtAddr)
  1702.     Address    virtAddr;
  1703. {
  1704.     int        i;
  1705.     unsigned    int    pte;
  1706.  
  1707.     for (i = 0; i < (VMMACH_SEG_SIZE / VMMACH_PAGE_SIZE_INT); i++) {
  1708.     pte = VmMachGetPageMap(virtAddr + (i * VMMACH_PAGE_SIZE_INT));
  1709.     if (pte & VMMACH_RESIDENT_BIT) {
  1710.         VmMachFlushPage(virtAddr + (i * VMMACH_PAGE_SIZE_INT));
  1711.     }
  1712.     }
  1713. }
  1714.  
  1715.  
  1716. /*
  1717.  * ----------------------------------------------------------------------------
  1718.  *
  1719.  * PMEGFree --
  1720.  *
  1721.  *      Return the given pmeg to the pmeg list.
  1722.  *
  1723.  * Results:
  1724.  *      None.
  1725.  *
  1726.  * Side effects:
  1727.  *      The pmeg is returned to the pmeg list.
  1728.  *
  1729.  * ----------------------------------------------------------------------------
  1730.  */
  1731. INTERNAL static void
  1732. PMEGFree(pmegNum)
  1733.     int     pmegNum;    /* Which pmeg to free */
  1734. {
  1735.     register    PMEG    *pmegPtr;
  1736.     struct PMEGseg    *segPtr, *nextPtr;
  1737.  
  1738.     pmegPtr = &pmegArray[pmegNum];
  1739.     /*
  1740.      * If this pmeg can never be freed then don't free it.  This case can
  1741.      * occur when a device is mapped into a user's address space.
  1742.      */
  1743.     if (pmegPtr->flags & PMEG_NEVER_FREE) {
  1744.     return;
  1745.     }
  1746.  
  1747.     if (pmegPtr->pageCount > 0) {
  1748.  
  1749.     /*
  1750.      * Deal with pages that are still cached in this pmeg.
  1751.      */
  1752.     VmMachPMEGZero(pmegNum);
  1753.     }
  1754.     if (pmegPtr->segInfo.segPtr != (Vm_Segment *)NIL) {
  1755.     for (segPtr = &pmegPtr->segInfo; segPtr != (struct PMEGseg *)NIL;) {
  1756.         if (segPtr->segPtr->machPtr == (VmMach_SegData *)NIL) {
  1757.         printf("PMEGFree(%d): seg %d has no machPtr!\n", pmegNum,
  1758.             segPtr->segPtr->segNum);
  1759.         } else {
  1760.         *GetHardSegPtr(segPtr->segPtr->machPtr, segPtr->hardSegNum) =
  1761.             VMMACH_INV_PMEG;
  1762.         }
  1763.         nextPtr = segPtr->nextLink;
  1764.         if (segPtr != &pmegPtr->segInfo) {
  1765.         free((char *)segPtr);
  1766.         }
  1767.         segPtr = nextPtr;
  1768.     }
  1769.     }
  1770.     pmegPtr->segInfo.nextLink = (struct PMEGseg *) NIL;
  1771.     pmegPtr->segInfo.segPtr = (Vm_Segment *) NIL;
  1772.  
  1773.     /*
  1774.      * I really don't understand the code here.  The original was the second
  1775.      * line.  The first line was to try to fix an error that shows up in
  1776.      * UnmapIntelPage(), but I've tried now to fix that error there, since the
  1777.      * second line breaks things elsewhere.
  1778.      */
  1779.     if (pmegPtr->pageCount == 0 || !(pmegPtr->flags & PMEG_DONT_ALLOC)) {
  1780.     List_Remove((List_Links *) pmegPtr);
  1781.     }
  1782.     pmegPtr->flags = 0;
  1783.     pmegPtr->lockCount = 0;
  1784.     /*
  1785.      * Put this pmeg at the front of the pmeg free list.
  1786.      */
  1787.     List_Insert((List_Links *) pmegPtr, LIST_ATFRONT(pmegFreeList));
  1788. }
  1789.  
  1790.  
  1791. /*
  1792.  * ----------------------------------------------------------------------------
  1793.  *
  1794.  * PMEGLock --
  1795.  *
  1796.  *      Increment the lock count on a pmeg.
  1797.  *
  1798.  * Results:
  1799.  *      TRUE if there was a valid PMEG behind the given hardware segment.
  1800.  *
  1801.  * Side effects:
  1802.  *      The lock count is incremented if there is a valid pmeg at the given
  1803.  *    hardware segment.
  1804.  *
  1805.  * ----------------------------------------------------------------------------
  1806.  */
  1807. ENTRY static Boolean
  1808. PMEGLock(machPtr, segNum)
  1809.     register VmMach_SegData    *machPtr;
  1810.     int                segNum;
  1811. {
  1812.     unsigned int pmegNum;
  1813.  
  1814.     MASTER_LOCK(vmMachMutexPtr);
  1815.  
  1816.     pmegNum = *GetHardSegPtr(machPtr, segNum);
  1817.     if (pmegNum != VMMACH_INV_PMEG) {
  1818.     pmegArray[pmegNum].lockCount++;
  1819.     MASTER_UNLOCK(vmMachMutexPtr);
  1820.     return(TRUE);
  1821.     } else {
  1822.     MASTER_UNLOCK(vmMachMutexPtr);
  1823.     return(FALSE);
  1824.     }
  1825. }
  1826.  
  1827.  
  1828. /*
  1829.  * ----------------------------------------------------------------------------
  1830.  *
  1831.  * VmMach_SetupContext --
  1832.  *
  1833.  *      Return the value of the context register for the given process.
  1834.  *    It is assumed that this routine is called on a uni-processor right
  1835.  *    before the process starts executing.
  1836.  *    
  1837.  * Results:
  1838.  *      None.
  1839.  *
  1840.  * Side effects:
  1841.  *      The context list is modified.
  1842.  *
  1843.  * ----------------------------------------------------------------------------
  1844.  */
  1845. ENTRY ClientData
  1846. VmMach_SetupContext(procPtr)
  1847.     register    Proc_ControlBlock    *procPtr;
  1848. {
  1849.     register    VmMach_Context    *contextPtr;
  1850.  
  1851.     MASTER_LOCK(vmMachMutexPtr);
  1852.  
  1853.     while (TRUE) {
  1854.     contextPtr = procPtr->vmPtr->machPtr->contextPtr;
  1855.     if (contextPtr != (VmMach_Context *)NIL) {
  1856.         if (contextPtr != &contextArray[VMMACH_KERN_CONTEXT]) {
  1857.         if (vm_Tracing) {
  1858.             Vm_ProcInfo    *vmPtr;
  1859.  
  1860.             vmPtr = procPtr->vmPtr;
  1861.             vmPtr->segPtrArray[VM_CODE]->traceTime = vmTraceTime;
  1862.             vmPtr->segPtrArray[VM_HEAP]->traceTime = vmTraceTime;
  1863.             vmPtr->segPtrArray[VM_STACK]->traceTime = vmTraceTime;
  1864.         }
  1865.         List_Move((List_Links *)contextPtr, LIST_ATREAR(contextList));
  1866.         }
  1867.         MASTER_UNLOCK(vmMachMutexPtr);
  1868.         return((ClientData)contextPtr->context);
  1869.     }
  1870.         SetupContext(procPtr);
  1871.     }
  1872. }
  1873.  
  1874.  
  1875. /*
  1876.  * ----------------------------------------------------------------------------
  1877.  *
  1878.  * SetupContext --
  1879.  *
  1880.  *      Initialize the context for the given process.  If the process does
  1881.  *    not have a context associated with it then one is allocated.
  1882.  *
  1883.  *    Note that this routine runs unsynchronized even though it is using
  1884.  *    internal structures.  See the note above while this is OK.  I
  1885.  *     eliminated the monitor lock because it is unnecessary anyway and
  1886.  *    it slows down context-switching.
  1887.  *    
  1888.  * Results:
  1889.  *      None.
  1890.  *
  1891.  * Side effects:
  1892.  *      The context field in the process table entry and the context list are
  1893.  *     both modified if a new context is allocated.
  1894.  *
  1895.  * ----------------------------------------------------------------------------
  1896.  */
  1897. INTERNAL static void
  1898. SetupContext(procPtr)
  1899.     register    Proc_ControlBlock    *procPtr;
  1900. {
  1901.     register    VmMach_Context    *contextPtr;
  1902.     register    VmMach_SegData    *segDataPtr;
  1903.     register    Vm_ProcInfo    *vmPtr;
  1904.     int        stolenContext    = FALSE;
  1905.  
  1906.     vmPtr = procPtr->vmPtr;
  1907.     contextPtr = vmPtr->machPtr->contextPtr;
  1908.  
  1909.     if (procPtr->genFlags & (PROC_KERNEL | PROC_NO_VM)) {
  1910.     /*
  1911.      * This is a kernel process or a process that is exiting.
  1912.      * Set the context to kernel and return.
  1913.      */
  1914.     VmMachSetContextReg(VMMACH_KERN_CONTEXT);
  1915.     vmPtr->machPtr->contextPtr = &contextArray[VMMACH_KERN_CONTEXT];
  1916.     return;
  1917.     }
  1918.  
  1919.     if (contextPtr == (VmMach_Context *)NIL) {
  1920.     /*
  1921.      * In this case there is no context setup for this process.  Therefore
  1922.      * we have to find a context, initialize the context table entry and 
  1923.      * initialize the context stuff in the proc table.
  1924.      */
  1925.     if (List_IsEmpty((List_Links *) contextList)) {
  1926.         panic("SetupContext: Context list empty\n");
  1927.     }
  1928.     /* 
  1929.      * Take the first context off of the context list.
  1930.      */
  1931.     contextPtr = (VmMach_Context *) List_First(contextList);
  1932.     if (contextPtr->flags & CONTEXT_IN_USE) {
  1933.         contextPtr->procPtr->vmPtr->machPtr->contextPtr =
  1934.                             (VmMach_Context *)NIL;
  1935.         vmStat.machDepStat.stealContext++;
  1936.         stolenContext = TRUE;
  1937.     }
  1938.     /*
  1939.      * Initialize the context table entry.
  1940.      */
  1941.     contextPtr->flags = CONTEXT_IN_USE;
  1942.     contextPtr->procPtr = procPtr;
  1943.     vmPtr->machPtr->contextPtr = contextPtr;
  1944.     VmMachSetContextReg((int)contextPtr->context);
  1945.     if (stolenContext) {
  1946.         VmMach_FlushCurrentContext();
  1947.     }
  1948.     /*
  1949.      * Set the context map.
  1950.      */
  1951.     {
  1952.         int            i;
  1953.         unsigned int    j;
  1954.  
  1955.         /*
  1956.          * Since user addresses are never higher than the bottom of the
  1957.          * hole in the address space, this will save something like 30ms
  1958.          * by ending at VMMACH_BOTTOM_OF_HOLE rather than mach_KernStart.
  1959.          */
  1960.         j = ((unsigned int)VMMACH_BOTTOM_OF_HOLE) >> VMMACH_SEG_SHIFT;
  1961.         for (i = 0; i < j; i++) {
  1962.         contextPtr->map[i] = VMMACH_INV_PMEG;
  1963.         }
  1964.     }
  1965.     segDataPtr = vmPtr->segPtrArray[VM_CODE]->machPtr;
  1966.     bcopy((Address)segDataPtr->segTablePtr, 
  1967.         (Address) (contextPtr->map + segDataPtr->offset),
  1968.         segDataPtr->numSegs * sizeof (VMMACH_SEG_NUM));
  1969.  
  1970.     segDataPtr = vmPtr->segPtrArray[VM_HEAP]->machPtr;
  1971.     bcopy((Address)segDataPtr->segTablePtr, 
  1972.         (Address) (contextPtr->map + segDataPtr->offset),
  1973.         segDataPtr->numSegs * sizeof (VMMACH_SEG_NUM));
  1974.  
  1975.     segDataPtr = vmPtr->segPtrArray[VM_STACK]->machPtr;
  1976.     bcopy((Address)segDataPtr->segTablePtr, 
  1977.         (Address) (contextPtr->map + segDataPtr->offset),
  1978.         segDataPtr->numSegs * sizeof (VMMACH_SEG_NUM));
  1979.     if (vmPtr->sharedSegs != (List_Links *)NIL) {
  1980.         Vm_SegProcList *segList;
  1981.         LIST_FORALL(vmPtr->sharedSegs,(List_Links *)segList) {
  1982.         segDataPtr = segList->segTabPtr->segPtr->machPtr;
  1983.         bcopy((Address)segDataPtr->segTablePtr, 
  1984.             (Address) (contextPtr->map+PageToSeg(segList->offset)),
  1985.             segDataPtr->numSegs);
  1986.         }
  1987.     }
  1988.     if (vmPtr->machPtr->mapSegPtr != (struct Vm_Segment *)NIL) {
  1989.         contextPtr->map[MAP_SEG_NUM] = vmPtr->machPtr->mapHardSeg;
  1990.     } else {
  1991.         contextPtr->map[MAP_SEG_NUM] = VMMACH_INV_PMEG;
  1992.     }
  1993.     /*
  1994.      * Push map out to hardware.
  1995.      */
  1996.     VmMachCopyUserSegMap(contextPtr->map);
  1997.     } else {
  1998.     VmMachSetContextReg((int)contextPtr->context);
  1999.     }
  2000.     List_Move((List_Links *)contextPtr, LIST_ATREAR(contextList));
  2001. }
  2002.  
  2003.  
  2004. /*
  2005.  * ----------------------------------------------------------------------------
  2006.  *
  2007.  * Vm_FreeContext --
  2008.  *
  2009.  *      Free the given context.
  2010.  *
  2011.  * Results:
  2012.  *      None.
  2013.  *
  2014.  * Side effects:
  2015.  *      The context table and context lists are modified.
  2016.  *
  2017.  * ----------------------------------------------------------------------------
  2018.  */
  2019. ENTRY void
  2020. VmMach_FreeContext(procPtr)
  2021.     register    Proc_ControlBlock    *procPtr;
  2022. {
  2023.     register    VmMach_Context    *contextPtr;
  2024.     register    VmMach_ProcData    *machPtr;
  2025.  
  2026.     MASTER_LOCK(vmMachMutexPtr);
  2027.  
  2028.     machPtr = procPtr->vmPtr->machPtr;
  2029.     contextPtr = machPtr->contextPtr;
  2030.     if (contextPtr == (VmMach_Context *)NIL ||
  2031.         contextPtr->context == VMMACH_KERN_CONTEXT) {
  2032.     MASTER_UNLOCK(vmMachMutexPtr);
  2033.     return;
  2034.     }
  2035.  
  2036.     List_Move((List_Links *)contextPtr, LIST_ATFRONT(contextList));
  2037.     contextPtr->flags = 0;
  2038.     machPtr->contextPtr = (VmMach_Context *)NIL;
  2039.  
  2040.     MASTER_UNLOCK(vmMachMutexPtr);
  2041. }
  2042.  
  2043.  
  2044. /*
  2045.  * ----------------------------------------------------------------------------
  2046.  *
  2047.  * VmMach_ReinitContext --
  2048.  *
  2049.  *      Free the current context and set up another one.  This is called
  2050.  *    by routines such as Proc_Exec that add things to the context and
  2051.  *    then have to abort or start a process running with a new image.
  2052.  *
  2053.  * Results:
  2054.  *      None.
  2055.  *
  2056.  * Side effects:
  2057.  *      The context table and context lists are modified.
  2058.  *
  2059.  * ----------------------------------------------------------------------------
  2060.  */
  2061. void
  2062. VmMach_ReinitContext(procPtr)
  2063.     register    Proc_ControlBlock    *procPtr;
  2064. {
  2065.     VmMach_FreeContext(procPtr);
  2066.     MASTER_LOCK(vmMachMutexPtr);
  2067.     procPtr->vmPtr->machPtr->contextPtr = (VmMach_Context *)NIL;
  2068.     SetupContext(procPtr);
  2069.     MASTER_UNLOCK(vmMachMutexPtr);
  2070. }
  2071.  
  2072. #if defined(sun2)
  2073.  
  2074. static int     allocatedPMEG;
  2075. static VmMachPTE intelSavedPTE;        /* The page table entry that is stored
  2076.                      * at the address that the intel page
  2077.                      * has to overwrite. */
  2078. static unsigned int intelPage;        /* The page frame that was allocated.*/
  2079. #endif
  2080.  
  2081.  
  2082. /*
  2083.  * ----------------------------------------------------------------------------
  2084.  *
  2085.  * VmMach_MapIntelPage --
  2086.  *
  2087.  *      Allocate and validate a page for the Intel Ethernet chip.  This routine
  2088.  *    is required in order to initialize the chip.  The chip expects 
  2089.  *    certain stuff to be at a specific virtual address when it is 
  2090.  *    initialized.  This routine sets things up so that the expected
  2091.  *    virtual address is accessible.
  2092.  *
  2093.  * Results:
  2094.  *      None.
  2095.  *
  2096.  * Side effects:
  2097.  *      The old pte stored at the virtual address and the page frame that is
  2098.  *    allocated are stored in static globals.
  2099.  *
  2100.  * ----------------------------------------------------------------------------
  2101.  */
  2102. /*ARGSUSED*/
  2103. void
  2104. VmMach_MapIntelPage(virtAddr) 
  2105.     Address    virtAddr; /* Virtual address where a page has to be validated
  2106.                  at. */
  2107. {
  2108. #if defined(sun2)
  2109.     VmMachPTE        pte;
  2110.     int            pmeg;
  2111.  
  2112.     /*
  2113.      * See if there is a PMEG already.  If not allocate one.
  2114.      */
  2115.     pmeg = VmMachGetSegMap(virtAddr);
  2116.     if (pmeg == VMMACH_INV_PMEG) {
  2117.     MASTER_LOCK(vmMachMutexPtr);
  2118.     /* No flush, since PMEGGet takes care of that. */
  2119.     allocatedPMEG = PMEGGet(vm_SysSegPtr, 
  2120.                 (unsigned)virtAddr >> VMMACH_SEG_SHIFT,
  2121.                 PMEG_DONT_ALLOC);
  2122.     MASTER_UNLOCK(vmMachMutexPtr);
  2123.     VmMachSetSegMap(virtAddr, allocatedPMEG);
  2124.     } else {
  2125.     allocatedPMEG = VMMACH_INV_PMEG;
  2126.     intelSavedPTE = VmMachGetPageMap(virtAddr);
  2127.     }
  2128.  
  2129.     /*
  2130.      * Set up the page table entry.
  2131.      */
  2132.     intelPage = Vm_KernPageAllocate();
  2133.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | VirtToPhysPage(intelPage);
  2134. #ifdef sun4
  2135. #ifdef NOTDEF
  2136.     pte |= VMMACH_DONT_CACHE_BIT;
  2137. #endif
  2138. #endif /* sun4 */
  2139.     /* No flush since this should never be cached. */
  2140.     VmMachSetPageMap(virtAddr, pte);
  2141. #endif /* sun2  */
  2142. #ifdef sun4
  2143.     VmMachPTE        pte;
  2144.     int            pmeg;
  2145.     int            oldContext;
  2146.     int            i;
  2147.  
  2148.     /*
  2149.      * See if there is a PMEG already.  If not allocate one.
  2150.      */
  2151.     pmeg = VmMachGetSegMap(virtAddr);
  2152.     if (pmeg == VMMACH_INV_PMEG) {
  2153.     MASTER_LOCK(vmMachMutexPtr);
  2154.     /* No flush, since PMEGGet takes care of that. */
  2155.     pmeg = PMEGGet(vm_SysSegPtr, 
  2156.                 (int)((unsigned)virtAddr) >> VMMACH_SEG_SHIFT,
  2157.                 PMEG_DONT_ALLOC);
  2158.     MASTER_UNLOCK(vmMachMutexPtr);
  2159.     VmMachSetSegMap(virtAddr, pmeg);
  2160.     } 
  2161.     oldContext = VmMachGetContextReg();
  2162.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  2163.     VmMachSetContextReg(i);
  2164.     VmMachSetSegMap(virtAddr, pmeg);
  2165.     }
  2166.     VmMachSetContextReg(oldContext);
  2167.     /*
  2168.      * Set up the page table entry.
  2169.      */
  2170.     pte = VmMachGetPageMap(virtAddr);
  2171.     if (pte == 0) {
  2172.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | VMMACH_DONT_CACHE_BIT |
  2173.           VirtToPhysPage(Vm_KernPageAllocate());
  2174.     SET_ALL_PAGE_MAP(virtAddr, pte);
  2175.     } 
  2176. #endif
  2177. }
  2178.  
  2179.  
  2180. /*
  2181.  * ----------------------------------------------------------------------------
  2182.  *
  2183.  * Vm_UnmapIntelPage --
  2184.  *
  2185.  *      Deallocate and invalidate a page for the intel chip.  This is a special
  2186.  *    case routine that is only for the intel ethernet chip.
  2187.  *
  2188.  * Results:
  2189.  *      None.
  2190.  *
  2191.  * Side effects:
  2192.  *      The hardware segment table associated with the segment
  2193.  *      is modified to invalidate the page.
  2194.  *
  2195.  * ----------------------------------------------------------------------------
  2196.  */
  2197. /*ARGSUSED*/
  2198. void
  2199. VmMach_UnmapIntelPage(virtAddr) 
  2200.     Address    virtAddr;
  2201. {
  2202. #if defined(sun2)
  2203.     PMEG        *pmegPtr;
  2204.     Boolean    found = FALSE;
  2205.  
  2206.     if (allocatedPMEG != VMMACH_INV_PMEG) {
  2207.     /*
  2208.      * Free up the PMEG.
  2209.      */
  2210.     /* No flush since this should never be cached. */
  2211.     VmMachSetPageMap(virtAddr, (VmMachPTE)0);
  2212.     VmMachSetSegMap(virtAddr, VMMACH_INV_PMEG);
  2213.  
  2214.     MASTER_LOCK(vmMachMutexPtr);
  2215.  
  2216.     /*
  2217.      * This is a little gross, but for some reason this pmeg has a 0
  2218.      * page count.  Since it has the PMEG_DONT_ALLOC flag set, it wasn't
  2219.      * removed from the pmegInuseList in PMEGGet().  So the remove done
  2220.      * in PMEGFree would remove it twice, unless we check.
  2221.      */
  2222.     LIST_FORALL(pmegInuseList, (List_Links *)pmegPtr) {
  2223.         if (pmegPtr == &pmegArray[allocatedPMEG]) {
  2224.         found = TRUE;
  2225.         }
  2226.     }
  2227.     if (!found) {
  2228.         pmegPtr = &pmegArray[allocatedPMEG];
  2229.         List_Insert((List_Links *) pmegPtr, LIST_ATREAR(pmegInuseList));
  2230.     }
  2231.     PMEGFree(allocatedPMEG);
  2232.  
  2233.     MASTER_UNLOCK(vmMachMutexPtr);
  2234.     } else {
  2235.     /*
  2236.      * Restore the saved pte and free the allocated page.
  2237.      */
  2238.     /* No flush since this should never be cached. */
  2239.     VmMachSetPageMap(virtAddr, intelSavedPTE);
  2240.     }
  2241.     Vm_KernPageFree(intelPage);
  2242. #endif
  2243. }
  2244.  
  2245.  
  2246. static Address        netMemAddr;
  2247. static unsigned int    netLastPage;
  2248.  
  2249.  
  2250. /*
  2251.  * ----------------------------------------------------------------------------
  2252.  *
  2253.  * InitNetMem --
  2254.  *
  2255.  *      Initialize the memory mappings for the network.
  2256.  *
  2257.  * Results:
  2258.  *      None.
  2259.  *
  2260.  * Side effects:
  2261.  *      PMEGS are allocated and initialized.
  2262.  *
  2263.  * ----------------------------------------------------------------------------
  2264.  */
  2265. static void
  2266. InitNetMem()
  2267. {
  2268.     VMMACH_SEG_NUM        pmeg;
  2269.     register VMMACH_SEG_NUM    *segTablePtr;
  2270.     int                i;
  2271.     int                j;
  2272.     int                lastSegNum;
  2273.     int                segNum;
  2274.     Address            virtAddr;
  2275.  
  2276.     /*
  2277.      * Allocate pmegs  for net mapping.
  2278.      */
  2279.     segNum = ((unsigned)VMMACH_NET_MAP_START) >> VMMACH_SEG_SHIFT;
  2280.     lastSegNum = ((unsigned)(VMMACH_NET_MAP_START+VMMACH_NET_MAP_SIZE-1)) /
  2281.               VMMACH_SEG_SIZE;
  2282.  
  2283.     for (i = 0, virtAddr = (Address)VMMACH_NET_MAP_START,
  2284.         segTablePtr = GetHardSegPtr(vm_SysSegPtr->machPtr, segNum);
  2285.      segNum <= lastSegNum;
  2286.          i++, virtAddr += VMMACH_SEG_SIZE, segNum++) {
  2287.     pmeg = VmMachGetSegMap(virtAddr);
  2288.     if (pmeg == VMMACH_INV_PMEG) {
  2289.         *(segTablePtr + i) = PMEGGet(vm_SysSegPtr, segNum, PMEG_DONT_ALLOC);
  2290.         VmMachSetSegMap(virtAddr, (int)*(segTablePtr + i));
  2291.     } else {
  2292.         *(segTablePtr + i) = pmeg;
  2293.     }
  2294.     /*
  2295.      * Propagate the new pmeg mapping to all contexts.
  2296.      */
  2297.     for (j = 0; j < VMMACH_NUM_CONTEXTS; j++) {
  2298.         if (j == VMMACH_KERN_CONTEXT) {
  2299.         continue;
  2300.         }
  2301.         VmMachSetContextReg(j);
  2302.         VmMachSetSegMap(virtAddr, (int)*(segTablePtr + i));
  2303.     }
  2304.     VmMachSetContextReg(VMMACH_KERN_CONTEXT);
  2305.     }
  2306.     /*
  2307.      * Repeat for the network memory range. 
  2308.      */
  2309.     segNum = ((unsigned)VMMACH_NET_MEM_START) >> VMMACH_SEG_SHIFT;
  2310.     lastSegNum = ((unsigned)(VMMACH_NET_MEM_START+VMMACH_NET_MEM_SIZE-1)) /
  2311.              VMMACH_SEG_SIZE;
  2312.  
  2313.     for (i = 0, virtAddr = (Address)VMMACH_NET_MEM_START,
  2314.         segTablePtr = GetHardSegPtr(vm_SysSegPtr->machPtr, segNum);
  2315.      segNum <= lastSegNum;
  2316.          i++, virtAddr += VMMACH_SEG_SIZE, segNum++) {
  2317.     pmeg = VmMachGetSegMap(virtAddr);
  2318.     if (pmeg == VMMACH_INV_PMEG) {
  2319.         *(segTablePtr + i) = PMEGGet(vm_SysSegPtr, segNum, PMEG_DONT_ALLOC);
  2320.         VmMachSetSegMap(virtAddr, (int)*(segTablePtr + i));
  2321.     } else {
  2322.         *(segTablePtr + i) = pmeg;
  2323.     }
  2324.     /*
  2325.      * Propagate the new pmeg mapping to all contexts.
  2326.      */
  2327.     for (j = 0; j < VMMACH_NUM_CONTEXTS; j++) {
  2328.         if (j == VMMACH_KERN_CONTEXT) {
  2329.         continue;
  2330.         }
  2331.         VmMachSetContextReg(j);
  2332.         VmMachSetSegMap(virtAddr, (int)*(segTablePtr + i));
  2333.     }
  2334.     VmMachSetContextReg(VMMACH_KERN_CONTEXT);
  2335.     }
  2336.  
  2337.     netMemAddr = (Address)VMMACH_NET_MEM_START;
  2338.     netLastPage = (((unsigned)VMMACH_NET_MEM_START) >> VMMACH_PAGE_SHIFT) - 1;
  2339. }
  2340.  
  2341. /*
  2342.  * ----------------------------------------------------------------------------
  2343.  *
  2344.  * VmMach_NetMemAlloc --
  2345.  *
  2346.  *      Allocate physical memory for a network driver.
  2347.  *
  2348.  * Results:
  2349.  *      The address where the memory is allocated at.
  2350.  *
  2351.  * Side effects:
  2352.  *      Memory allocated.
  2353.  *
  2354.  * ----------------------------------------------------------------------------
  2355.  */
  2356. Address
  2357. VmMach_NetMemAlloc(numBytes)
  2358.     int    numBytes;    /* Number of bytes of memory to allocated. */
  2359. {
  2360.     VmMachPTE    pte;
  2361.     Address    retAddr;
  2362.     Address    maxAddr;
  2363.     Address    virtAddr;
  2364.     static Boolean initialized = FALSE;
  2365.  
  2366.     if (!initialized) {
  2367.     InitNetMem();
  2368.     initialized = TRUE;
  2369.     }
  2370.  
  2371.     retAddr = netMemAddr;
  2372.     netMemAddr += (numBytes + 7) & ~7;    /* is this necessary for sun4? */
  2373.     /*
  2374.      * Panic if we are out of memory.  
  2375.      */
  2376.     if (netMemAddr > (Address) (VMMACH_NET_MEM_START + VMMACH_NET_MEM_SIZE)) {
  2377.     panic("VmMach_NetMemAlloc: Out of network memory\n");
  2378.     }
  2379.  
  2380.     maxAddr = (Address) ((netLastPage + 1) * VMMACH_PAGE_SIZE - 1);
  2381.  
  2382.     /*
  2383.      * Add new pages to the virtual address space until we have added enough
  2384.      * to handle this memory request.
  2385.      */
  2386.     while (netMemAddr - 1 > maxAddr) {
  2387.     maxAddr += VMMACH_PAGE_SIZE;
  2388.     netLastPage++;
  2389.     virtAddr = (Address) (netLastPage << VMMACH_PAGE_SHIFT);
  2390.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT |
  2391. #ifdef sun4c
  2392.           /*
  2393.            * For some reason on the sparcStation, we can't allow the
  2394.            * network pages to be cached. This is really a problem and it
  2395.            * totally breaks the driver.
  2396.            */
  2397.           VMMACH_DONT_CACHE_BIT | 
  2398. #endif
  2399.           VirtToPhysPage(Vm_KernPageAllocate());
  2400.     SET_ALL_PAGE_MAP(virtAddr, pte);
  2401.     }
  2402.  
  2403.     bzero(retAddr, numBytes);
  2404.     return(retAddr);
  2405. }
  2406.  
  2407.  
  2408. /*
  2409.  *----------------------------------------------------------------------
  2410.  *
  2411.  * VmMach_NetMapPacket --
  2412.  *
  2413.  *    Map the packet pointed to by the scatter-gather array.
  2414.  *
  2415.  * Results:
  2416.  *    None.
  2417.  *
  2418.  * Side effects:
  2419.  *    The outScatGathArray is filled in with pointers to where the
  2420.  *    packet was mapped in.
  2421.  *
  2422.  *----------------------------------------------------------------------
  2423.  */
  2424. void
  2425. VmMach_NetMapPacket(inScatGathPtr, scatGathLength, outScatGathPtr)
  2426.     register Net_ScatterGather    *inScatGathPtr;
  2427.     register int        scatGathLength;
  2428.     register Net_ScatterGather    *outScatGathPtr;
  2429. {
  2430.     register Address    mapAddr;
  2431.     register Address    endAddr;
  2432. #ifndef sun4c
  2433.     int            segNum;
  2434.     int            pageNum = 0;
  2435. #endif
  2436.  
  2437. #ifdef sun4c
  2438.     /*
  2439.      * The network driver on the sparcstation never accesses the data
  2440.      * through the cache, so there should be no need to flush it.
  2441.      */
  2442.     for (mapAddr = (Address)VMMACH_NET_MAP_START;
  2443.          scatGathLength > 0;
  2444.          scatGathLength--, inScatGathPtr++, outScatGathPtr++) {
  2445.         outScatGathPtr->length = inScatGathPtr->length;
  2446.         if (inScatGathPtr->length == 0) {
  2447.             continue;
  2448.         }
  2449.         /*
  2450.          * Map the piece of the packet in.  Note that we know that a packet
  2451.          * piece is no longer than 1536 bytes so we know that we will need
  2452.          * at most two page table entries to map a piece in.
  2453.          */
  2454.         VmMachSetPageMap(mapAddr, VmMachGetPageMap(inScatGathPtr->bufAddr));
  2455.         outScatGathPtr->bufAddr =
  2456.             mapAddr + ((unsigned)inScatGathPtr->bufAddr & VMMACH_OFFSET_MASK);
  2457.         mapAddr += VMMACH_PAGE_SIZE_INT;
  2458.         endAddr = inScatGathPtr->bufAddr + inScatGathPtr->length - 1;
  2459.         if (((unsigned)inScatGathPtr->bufAddr & ~VMMACH_OFFSET_MASK_INT) !=
  2460.             ((unsigned)endAddr & ~VMMACH_OFFSET_MASK_INT)) {
  2461.             VmMachSetPageMap(mapAddr, VmMachGetPageMap(endAddr));
  2462.             mapAddr += VMMACH_PAGE_SIZE_INT;
  2463.         }
  2464.     }
  2465. #else
  2466.     for (segNum = 0 ; scatGathLength > 0;
  2467.         scatGathLength--, inScatGathPtr++, outScatGathPtr++) {
  2468.     outScatGathPtr->length = inScatGathPtr->length;
  2469.     if (inScatGathPtr->length == 0) {
  2470.         continue;
  2471.     }
  2472.     /*
  2473.      * For the first (VMMACH_NUM_NET_SEGS) - 1 elements in the
  2474.      * scatter gather array, map each element into a segment, aligned
  2475.      * with the mapping pages so that cache flushes will be avoided.
  2476.      */
  2477.     if (segNum < VMMACH_NUM_NET_SEGS - 1) {
  2478.         /* do silly mapping */
  2479.         mapAddr = (Address)VMMACH_NET_MAP_START +
  2480.             (segNum * VMMACH_SEG_SIZE);
  2481.         /* align to same cache boundary */
  2482.         mapAddr += ((unsigned int)inScatGathPtr->bufAddr &
  2483.             (VMMACH_CACHE_SIZE - 1));
  2484.         /* set addr to beginning of page */
  2485.         (unsigned int) mapAddr &= ~VMMACH_OFFSET_MASK;
  2486.         VmMachFlushPage(mapAddr);
  2487.         VmMachSetPageMap(mapAddr, VmMachGetPageMap(inScatGathPtr->bufAddr));
  2488.         outScatGathPtr->bufAddr = (Address) ((unsigned)mapAddr +
  2489.             ((unsigned)inScatGathPtr->bufAddr & VMMACH_OFFSET_MASK));
  2490.         mapAddr += VMMACH_PAGE_SIZE_INT;
  2491.         endAddr = (Address)inScatGathPtr->bufAddr +
  2492.             inScatGathPtr->length - 1;
  2493.         if (((unsigned)inScatGathPtr->bufAddr & ~VMMACH_OFFSET_MASK_INT) !=
  2494.         ((unsigned)endAddr & ~VMMACH_OFFSET_MASK_INT)) {
  2495.         VmMachFlushPage(mapAddr);
  2496.         VmMachSetPageMap(mapAddr, VmMachGetPageMap(endAddr));
  2497.         }
  2498.         segNum++;
  2499.     } else {
  2500.         /*
  2501.          * For elements beyond the last one, map them all into the
  2502.          * last mapping segment.  Cache flushing will be necessary for
  2503.          * these.
  2504.          */
  2505.         mapAddr = (Address)VMMACH_NET_MAP_START +
  2506.             (segNum * VMMACH_SEG_SIZE) + (pageNum * VMMACH_PAGE_SIZE);
  2507.         VmMachFlushPage(inScatGathPtr->bufAddr);
  2508.         VmMachFlushPage(mapAddr);
  2509.         VmMachSetPageMap(mapAddr, VmMachGetPageMap(inScatGathPtr->bufAddr));
  2510.         outScatGathPtr->bufAddr = (Address) ((unsigned)mapAddr +
  2511.             ((unsigned)inScatGathPtr->bufAddr & VMMACH_OFFSET_MASK));
  2512.         mapAddr += VMMACH_PAGE_SIZE_INT;
  2513.         pageNum++;
  2514.         endAddr = (Address)inScatGathPtr->bufAddr +
  2515.             inScatGathPtr->length - 1;
  2516.         if (((unsigned)inScatGathPtr->bufAddr & ~VMMACH_OFFSET_MASK_INT) !=
  2517.         ((unsigned)endAddr & ~VMMACH_OFFSET_MASK_INT)) {
  2518.         VmMachFlushPage(endAddr);
  2519.         VmMachFlushPage(mapAddr);
  2520.         VmMachSetPageMap(mapAddr, VmMachGetPageMap(endAddr));
  2521.         pageNum++;
  2522.         }
  2523.         printf("MapPacket: segNum is %d, pageNum is %d\n", segNum, pageNum);
  2524.     }
  2525.     }
  2526. #endif /* sun4c */
  2527. }
  2528.  
  2529.  
  2530.  
  2531. /*
  2532.  *----------------------------------------------------------------------
  2533.  *
  2534.  * VmMach_VirtAddrParse --
  2535.  *
  2536.  *    See if the given address falls into the special mapping segment.
  2537.  *    If so parse it for our caller.
  2538.  *
  2539.  * Results:
  2540.  *    TRUE if the address fell into the special mapping segment, FALSE
  2541.  *    otherwise.
  2542.  *
  2543.  * Side effects:
  2544.  *    *transVirtAddrPtr may be filled in.
  2545.  *
  2546.  *----------------------------------------------------------------------
  2547.  */
  2548. Boolean
  2549. VmMach_VirtAddrParse(procPtr, virtAddr, transVirtAddrPtr)
  2550.     Proc_ControlBlock        *procPtr;
  2551.     Address            virtAddr;
  2552.     register    Vm_VirtAddr    *transVirtAddrPtr;
  2553. {
  2554.     Address    origVirtAddr;
  2555.     Boolean    retVal;
  2556.  
  2557. #ifdef sun4
  2558.     if (!VMMACH_ADDR_CHECK(virtAddr)) {
  2559.     panic("VmMach_VirtAddrParse: virt addr 0x%x falls in illegal range!\n",
  2560.         virtAddr);
  2561.     }
  2562. #endif sun4
  2563.     if (virtAddr >= (Address)VMMACH_MAP_SEG_ADDR && 
  2564.         virtAddr < (Address)mach_KernStart) {
  2565.     /*
  2566.      * The address falls into the special mapping segment.  Translate
  2567.      * the address back to the segment that it falls into.
  2568.      */
  2569.     transVirtAddrPtr->segPtr = procPtr->vmPtr->machPtr->mapSegPtr;
  2570.     origVirtAddr = 
  2571.         (Address)(procPtr->vmPtr->machPtr->mapHardSeg << VMMACH_SEG_SHIFT);
  2572.     transVirtAddrPtr->sharedPtr = procPtr->vmPtr->machPtr->sharedPtr;
  2573.      if (transVirtAddrPtr->segPtr->type == VM_SHARED) {
  2574.          origVirtAddr -= ( transVirtAddrPtr->segPtr->offset
  2575.              >>(VMMACH_SEG_SHIFT-VMMACH_PAGE_SHIFT))
  2576.              << VMMACH_SEG_SHIFT;
  2577.         origVirtAddr += segOffset(transVirtAddrPtr)<<VMMACH_PAGE_SHIFT;
  2578.      }
  2579.     origVirtAddr += (unsigned int)virtAddr & (VMMACH_SEG_SIZE - 1);
  2580.     transVirtAddrPtr->page = (unsigned) (origVirtAddr) >> VMMACH_PAGE_SHIFT;
  2581.     transVirtAddrPtr->offset = (unsigned)virtAddr & VMMACH_OFFSET_MASK;
  2582.     transVirtAddrPtr->flags = USING_MAPPED_SEG;
  2583.     retVal = TRUE;
  2584.     } else {
  2585.     retVal = FALSE;
  2586.     }
  2587.     return(retVal);
  2588. }
  2589.  
  2590. /*
  2591.  * We use this array to flush the cache by touching entries at the correct
  2592.  * offsets to clear the corresponding parts of the direct-mapped cache.
  2593.  */
  2594. volatile char    cacheFlusherArray[VMMACH_NUM_CACHE_LINES *
  2595.     VMMACH_CACHE_LINE_SIZE * 2];
  2596.  
  2597.  
  2598. /*
  2599.  *----------------------------------------------------------------------
  2600.  *
  2601.  * FlushWholeCache --
  2602.  *
  2603.  *    Flush the whole cache.  It is important that the compiler not
  2604.  *    optimize out this loop!
  2605.  *
  2606.  * Results:
  2607.  *    None.
  2608.  *
  2609.  * Side effects:
  2610.  *    Cache flushed.
  2611.  *
  2612.  *----------------------------------------------------------------------
  2613.  */
  2614. static void
  2615. FlushWholeCache()
  2616. {
  2617.     int    i;
  2618.     char junk;
  2619.     register volatile char *cacheFlusherArrayPtr;
  2620.  
  2621.     cacheFlusherArrayPtr = cacheFlusherArray;
  2622.     for (i = 0; i < VMMACH_CACHE_SIZE; i += VMMACH_CACHE_LINE_SIZE) {
  2623.     junk = cacheFlusherArrayPtr[i];
  2624.     }
  2625.     return;
  2626. }
  2627.  
  2628. #if 0 /* dead code shirriff 9/90 */
  2629. char    bigBuf[VMMACH_PAGE_SIZE_INT * 2];
  2630. ReturnStatus
  2631. VmMachTestCacheFlush()
  2632. {
  2633.     unsigned int    pte1;
  2634.     unsigned int    pte2;
  2635.     unsigned int    savePte1;
  2636.     unsigned int    savePte2;
  2637.     Address    virtAddr1;
  2638.     Address    virtAddr2;
  2639.     unsigned    int    saveValue11, saveValue12, saveValue21, saveValue22;
  2640.     unsigned    int    saveValue3;
  2641.     unsigned    int    endSave3;
  2642.     unsigned    int    endSave11, endSave12, endSave21, endSave22;
  2643.  
  2644.  
  2645.     /* first addr at first page */
  2646.     virtAddr1 = (Address) bigBuf;
  2647.     /* first addr's pte */
  2648.     pte1 = VmMachGetPageMap(virtAddr1);
  2649.     pte2 = VmMachGetPageMap(virtAddr1 + 254);
  2650.  
  2651.     /* second addr at second page */
  2652.     virtAddr2 = (Address) (bigBuf + VMMACH_PAGE_SIZE_INT);
  2653.     /* save second addr's pte */
  2654.     savePte1 = VmMachGetPageMap(virtAddr2);
  2655.     savePte2 = VmMachGetPageMap(virtAddr2 + 254);
  2656.  
  2657.     /* flush second page's virtAddrs out of cache */
  2658.     VmMachFlushPage(virtAddr2);
  2659.     VmMachFlushPage(virtAddr2 + 254);
  2660.     /* give second addr the same pte as first */
  2661.     VmMachSetPageMap(virtAddr2, pte1);
  2662.     VmMachSetPageMap(virtAddr2 + 254, pte2);
  2663.  
  2664.     /* get current virtAddr1 value */
  2665.     saveValue11 = *virtAddr1;
  2666.     endSave11 = *(virtAddr1 + 254);
  2667.  
  2668.     /* get current virtAddr2 value - after flush, so really from memory */
  2669.     saveValue21 = *virtAddr2;
  2670.     endSave21 = *(virtAddr2 + 254);
  2671.  
  2672.     /* flush virtAddr2 from memory again */
  2673.     VmMachFlushPage(virtAddr2);
  2674.     VmMachFlushPage(virtAddr2 + 254);
  2675.  
  2676.     /* is something weird?  saveValue12 should equal saveValue11 */
  2677.     saveValue12 = *virtAddr1;
  2678.     endSave12 = *(virtAddr1 + 254);
  2679.  
  2680.     /* give virtAddr1 new value */
  2681.     *virtAddr1 = ~saveValue11;
  2682.     *(virtAddr1 + 254) = ~endSave11;
  2683.  
  2684.     /* should only be in cache */
  2685.     saveValue3 = *virtAddr2;
  2686.     endSave3 = *(virtAddr2 + 254);
  2687.     if (saveValue3 == ~saveValue11) {
  2688.     return FAILURE;
  2689.     }
  2690.     if (endSave3 == ~endSave11) {
  2691.     return FAILURE;
  2692.     }
  2693.     /* get rid of virtAddr2 again */
  2694.     VmMachFlushPage(virtAddr2);
  2695.     VmMachFlushPage(virtAddr2 + 254);
  2696.  
  2697.     /* Now try icky range flush */
  2698.     VmMach_FlushByteRange(virtAddr1, 254);
  2699.  
  2700.     /* Did it get to memory? */
  2701.     saveValue22 = *virtAddr2;
  2702.     endSave22 = *(virtAddr2 + 254);
  2703.  
  2704.     /* restore pte of second addr */
  2705.     VmMachSetPageMap(virtAddr2, savePte1);
  2706.     VmMachSetPageMap(virtAddr2 + 254, savePte2);
  2707.  
  2708.     if (saveValue22 != ~saveValue11) {
  2709.     return FAILURE;
  2710.     }
  2711.     if (endSave22 != ~endSave11) {
  2712.     return FAILURE;
  2713.     }
  2714. #ifdef lint
  2715.     endSave21 = endSave21;
  2716.     endSave12 = endSave12;
  2717.     saveValue21 = saveValue21;
  2718.     saveValue12 = saveValue12;
  2719. #endif
  2720.     return SUCCESS;
  2721. }
  2722. #endif /* dead code */
  2723.  
  2724.  
  2725. /*
  2726.  *----------------------------------------------------------------------
  2727.  *
  2728.  * VmMach_CopyInProc --
  2729.  *
  2730.  *    Copy from another process's address space into the current address
  2731.  *    space.   This is done by mapping the other processes segment into
  2732.  *    the current VAS and then doing the copy.  It assumed that this 
  2733.  *    routine is called with the source process locked such that its
  2734.  *    VM will not go away while we are doing this copy.
  2735.  *
  2736.  * Results:
  2737.  *    SUCCESS if the copy succeeded, SYS_ARG_NOACCESS if fromAddr is invalid.
  2738.  *
  2739.  * Side effects:
  2740.  *    What toAddr points to is modified.
  2741.  *
  2742.  *----------------------------------------------------------------------
  2743.  */
  2744. /*ARGSUSED*/
  2745. ReturnStatus
  2746. VmMach_CopyInProc(numBytes, fromProcPtr, fromAddr, virtAddrPtr,
  2747.           toAddr, toKernel)
  2748.     int     numBytes;        /* The maximum number of bytes to 
  2749.                        copy in. */
  2750.     Proc_ControlBlock    *fromProcPtr;    /* Which process to copy from.*/
  2751.     Address        fromAddr;    /* The address to copy from */
  2752.     Vm_VirtAddr        *virtAddrPtr;
  2753.     Address        toAddr;        /* The address to copy to */
  2754.     Boolean        toKernel;    /* This copy is happening to the
  2755.                      * kernel's address space. */
  2756. {
  2757.     ReturnStatus        status = SUCCESS;
  2758.     register VmMach_ProcData    *machPtr;
  2759.     Proc_ControlBlock        *toProcPtr;
  2760.     int                segOffset;
  2761.     int                bytesToCopy;
  2762.     int                oldContext;
  2763.  
  2764.     toProcPtr = Proc_GetCurrentProc();
  2765.     machPtr = toProcPtr->vmPtr->machPtr;
  2766.     machPtr->mapSegPtr = virtAddrPtr->segPtr;
  2767.     machPtr->mapHardSeg = (unsigned int) (fromAddr) >> VMMACH_SEG_SHIFT;
  2768.     machPtr->sharedPtr = virtAddrPtr->sharedPtr;
  2769.     if (virtAddrPtr->sharedPtr != (Vm_SegProcList*)NIL) {
  2770.     /*
  2771.      * Mangle the segment offset so that it matches the offset
  2772.      * of the mapped segment.
  2773.      */
  2774.     if (debugVmStubs) {
  2775.         printf("Copying in shared segment\n");
  2776.     }
  2777.     machPtr->mapHardSeg -= (virtAddrPtr->sharedPtr->offset<<
  2778.         VMMACH_PAGE_SHIFT_INT)>>VMMACH_SEG_SHIFT;
  2779.     machPtr->mapHardSeg += machPtr->mapSegPtr->machPtr->offset;
  2780.     }
  2781.  
  2782. #ifdef sun4
  2783.     /*
  2784.      * Since this is a cross-address-space copy, we must make sure everything
  2785.      * has been flushed to the stack from our windows so that we don't
  2786.      * miss stuff on the stack not yet flushed. 
  2787.      */
  2788.     Mach_FlushWindowsToStack();
  2789. #endif
  2790.  
  2791.     /*
  2792.      * Do a hardware segment's worth at a time until done.
  2793.      */
  2794.     while (numBytes > 0 && status == SUCCESS) {
  2795.     segOffset = (unsigned int)fromAddr & (VMMACH_SEG_SIZE - 1);
  2796.     bytesToCopy = VMMACH_SEG_SIZE - segOffset;
  2797.     if (bytesToCopy > numBytes) {
  2798.         bytesToCopy = numBytes;
  2799.     }
  2800.     /*
  2801.      * First try quick and dirty copy.  If it fails, do regular copy.
  2802.      */
  2803.     if (fromProcPtr->vmPtr->machPtr->contextPtr != (VmMach_Context *)NIL) {
  2804.         unsigned int    fromContext;
  2805.         unsigned int    toContext;
  2806.  
  2807.         toContext = VmMachGetContextReg();
  2808.         fromContext = fromProcPtr->vmPtr->machPtr->contextPtr->context;
  2809.  
  2810.         status = VmMachQuickNDirtyCopy(bytesToCopy, fromAddr, toAddr,
  2811.         fromContext, toContext);
  2812.         VmMachSetContextReg((int)toContext);
  2813.  
  2814.         if (status == SUCCESS) {
  2815.         numBytes -= bytesToCopy;
  2816.         fromAddr += bytesToCopy;
  2817.         toAddr += bytesToCopy;
  2818.         continue;
  2819.         }
  2820.     }
  2821.     /*
  2822.      * Flush segment in context of fromProcPtr.  If the context is NIL, then
  2823.      * we can't and don't have to flush it, since it will be flushed
  2824.      * before being reused.
  2825.      */
  2826.     if (fromProcPtr->vmPtr->machPtr->contextPtr != (VmMach_Context *)NIL) {
  2827.         oldContext = VmMachGetContextReg();
  2828.         VmMachSetContextReg(
  2829.             (int)fromProcPtr->vmPtr->machPtr->contextPtr->context);
  2830.         VmMachFlushSegment(fromAddr);
  2831.         VmMachSetContextReg(oldContext);
  2832.     }
  2833.     /*
  2834.      * Push out the hardware segment.
  2835.      */
  2836.     WriteHardMapSeg(machPtr);
  2837.     /*
  2838.      * Do the copy.
  2839.      */
  2840.     toProcPtr->vmPtr->vmFlags |= VM_COPY_IN_PROGRESS;
  2841.     status = VmMachDoCopy(bytesToCopy,
  2842.                   (Address)(VMMACH_MAP_SEG_ADDR + segOffset),
  2843.                   toAddr);
  2844.     toProcPtr->vmPtr->vmFlags &= ~VM_COPY_IN_PROGRESS;
  2845.     if (status == SUCCESS) {
  2846.         numBytes -= bytesToCopy;
  2847.         fromAddr += bytesToCopy;
  2848.         toAddr += bytesToCopy;
  2849.     } else {
  2850.         status = SYS_ARG_NOACCESS;
  2851.     }
  2852.     /*
  2853.      * Zap the hardware segment.
  2854.      */
  2855.     VmMachFlushSegment((Address) VMMACH_MAP_SEG_ADDR);
  2856.     VmMachSetSegMap((Address)VMMACH_MAP_SEG_ADDR, VMMACH_INV_PMEG); 
  2857.     machPtr->mapHardSeg++;
  2858.     }
  2859.     machPtr->mapSegPtr = (struct Vm_Segment *)NIL;
  2860.     return(status);
  2861. }
  2862.  
  2863.  
  2864. /*
  2865.  *----------------------------------------------------------------------
  2866.  *
  2867.  * VmMach_CopyOutProc --
  2868.  *
  2869.  *    Copy from the current VAS to another processes VAS.  This is done by 
  2870.  *    mapping the other processes segment into the current VAS and then 
  2871.  *    doing the copy.  It assumed that this routine is called with the dest
  2872.  *    process locked such that its VM will not go away while we are doing
  2873.  *    the copy.
  2874.  *
  2875.  * Results:
  2876.  *    SUCCESS if the copy succeeded, SYS_ARG_NOACCESS if fromAddr is invalid.
  2877.  *
  2878.  * Side effects:
  2879.  *    What toAddr points to is modified.
  2880.  *
  2881.  *----------------------------------------------------------------------
  2882.  */
  2883. /*ARGSUSED*/
  2884. ReturnStatus
  2885. VmMach_CopyOutProc(numBytes, fromAddr, fromKernel, toProcPtr, toAddr,
  2886.            virtAddrPtr)
  2887.     int         numBytes;    /* The maximum number of bytes to 
  2888.                        copy in. */
  2889.     Address        fromAddr;    /* The address to copy from */
  2890.     Boolean        fromKernel;    /* This copy is happening to the
  2891.                      * kernel's address space. */
  2892.     Proc_ControlBlock    *toProcPtr;    /* Which process to copy from.*/
  2893.     Address        toAddr;        /* The address to copy to */
  2894.     Vm_VirtAddr        *virtAddrPtr;
  2895. {
  2896.     ReturnStatus        status = SUCCESS;
  2897.     register VmMach_ProcData    *machPtr;
  2898.     Proc_ControlBlock        *fromProcPtr;
  2899.     int                segOffset;
  2900.     int                bytesToCopy;
  2901.     int                oldContext;
  2902.  
  2903.  
  2904.     fromProcPtr = Proc_GetCurrentProc();
  2905.     machPtr = fromProcPtr->vmPtr->machPtr;
  2906.     machPtr->mapSegPtr = virtAddrPtr->segPtr;
  2907.     machPtr->mapHardSeg = (unsigned int) (toAddr) >> VMMACH_SEG_SHIFT;
  2908.     machPtr->sharedPtr = virtAddrPtr->sharedPtr;
  2909.     if (virtAddrPtr->sharedPtr != (Vm_SegProcList*)NIL) {
  2910.     /*
  2911.      * Mangle the segment offset so that it matches the offset
  2912.      * of the mapped segment.
  2913.      */
  2914.     if (debugVmStubs) {
  2915.         printf("Copying out shared segment\n");
  2916.     }
  2917.     machPtr->mapHardSeg -= (virtAddrPtr->sharedPtr->offset<<
  2918.         VMMACH_PAGE_SHIFT_INT)>>VMMACH_SEG_SHIFT;
  2919.     machPtr->mapHardSeg += machPtr->mapSegPtr->machPtr->offset;
  2920.     }
  2921.  
  2922. #ifdef sun4
  2923.     /*
  2924.      * Since this is a cross-address-space copy, we must make sure everything
  2925.      * has been flushed to the stack from our windows so that we don't
  2926.      * get stuff from windows overwriting stuff we copy to the stack later
  2927.      * when they're flushed.
  2928.      */
  2929.     Mach_FlushWindowsToStack();
  2930. #endif
  2931.  
  2932.     /*
  2933.      * Do a hardware segment's worth at a time until done.
  2934.      */
  2935.     while (numBytes > 0 && status == SUCCESS) {
  2936.     segOffset = (unsigned int)toAddr & (VMMACH_SEG_SIZE - 1);
  2937.     bytesToCopy = VMMACH_SEG_SIZE - segOffset;
  2938.     if (bytesToCopy > numBytes) {
  2939.         bytesToCopy = numBytes;
  2940.     }
  2941.     /*
  2942.      * First try quick and dirty copy.  If it fails, do regular copy.
  2943.      */
  2944.     if (toProcPtr->vmPtr->machPtr->contextPtr != (VmMach_Context *)NIL) {
  2945.         unsigned int    fromContext;
  2946.         unsigned int    toContext;
  2947.  
  2948.         fromContext = VmMachGetContextReg();
  2949.         toContext = toProcPtr->vmPtr->machPtr->contextPtr->context;
  2950.  
  2951.         status = VmMachQuickNDirtyCopy(bytesToCopy, fromAddr, toAddr,
  2952.             fromContext, toContext);
  2953.         VmMachSetContextReg((int)fromContext);
  2954.  
  2955.         if (status == SUCCESS) {
  2956.         numBytes -= bytesToCopy;
  2957.         fromAddr += bytesToCopy;
  2958.         toAddr += bytesToCopy;
  2959.         continue;
  2960.         }
  2961.     }
  2962.     /*
  2963.      * Flush segment in context of toProcPtr.  If the context is NIL, then
  2964.      * we can't and don't have to flush it, since it will be flushed before
  2965.      * being re-used.
  2966.      */
  2967.     if (toProcPtr->vmPtr->machPtr->contextPtr != (VmMach_Context *)NIL) {
  2968.         oldContext = VmMachGetContextReg();
  2969.         VmMachSetContextReg(
  2970.             (int)toProcPtr->vmPtr->machPtr->contextPtr->context);
  2971.         VmMachFlushSegment(toAddr);
  2972.         VmMachSetContextReg(oldContext);
  2973.     }
  2974.     /*
  2975.      * Push out the hardware segment.
  2976.      */
  2977.     WriteHardMapSeg(machPtr);
  2978.     /*
  2979.      * Do the copy.
  2980.      */
  2981.     fromProcPtr->vmPtr->vmFlags |= VM_COPY_IN_PROGRESS;
  2982.     status = VmMachDoCopy(bytesToCopy, fromAddr,
  2983.               (Address) (VMMACH_MAP_SEG_ADDR + segOffset));
  2984.     fromProcPtr->vmPtr->vmFlags &= ~VM_COPY_IN_PROGRESS;
  2985.     if (status == SUCCESS) {
  2986.         numBytes -= bytesToCopy;
  2987.         fromAddr += bytesToCopy;
  2988.         toAddr += bytesToCopy;
  2989.     } else {
  2990.         status = SYS_ARG_NOACCESS;
  2991.     }
  2992.     /*
  2993.      * Zap the hardware segment.
  2994.      */
  2995.  
  2996.     /* Flush this in current context */
  2997.     VmMachFlushSegment((Address) VMMACH_MAP_SEG_ADDR);
  2998.     VmMachSetSegMap((Address)VMMACH_MAP_SEG_ADDR, VMMACH_INV_PMEG); 
  2999.  
  3000.     machPtr->mapHardSeg++;
  3001.     }
  3002.     machPtr->mapSegPtr = (struct Vm_Segment *)NIL;
  3003.     return(status);
  3004. }
  3005.  
  3006.  
  3007. /*
  3008.  *----------------------------------------------------------------------
  3009.  *
  3010.  * WriteHardMapSeg --
  3011.  *
  3012.  *    Push the hardware segment map entry out to the hardware for the
  3013.  *    given mapped segment.
  3014.  *
  3015.  * Results:
  3016.  *    None.
  3017.  *
  3018.  * Side effects:
  3019.  *    Hardware segment modified.
  3020.  *
  3021.  *----------------------------------------------------------------------
  3022.  */
  3023. ENTRY static void
  3024. WriteHardMapSeg(machPtr)
  3025.     VmMach_ProcData    *machPtr;
  3026. {
  3027.     MASTER_LOCK(vmMachMutexPtr);
  3028.  
  3029.     if (machPtr->contextPtr != (VmMach_Context *) NIL) {
  3030.     machPtr->contextPtr->map[MAP_SEG_NUM] = 
  3031.         (int)*GetHardSegPtr(machPtr->mapSegPtr->machPtr,
  3032.         machPtr->mapHardSeg);
  3033.     }
  3034.     VmMachSetSegMap((Address)VMMACH_MAP_SEG_ADDR, 
  3035.      (int)*GetHardSegPtr(machPtr->mapSegPtr->machPtr, machPtr->mapHardSeg));
  3036.  
  3037.     MASTER_UNLOCK(vmMachMutexPtr);
  3038. }
  3039.  
  3040.  
  3041. /*
  3042.  *----------------------------------------------------------------------
  3043.  *
  3044.  * VmMach_SetSegProt --
  3045.  *
  3046.  *    Change the protection in the page table for the given range of bytes
  3047.  *    for the given segment.
  3048.  *
  3049.  * Results:
  3050.  *    None.
  3051.  *
  3052.  * Side effects:
  3053.  *    Page table may be modified for the segment.
  3054.  *
  3055.  *----------------------------------------------------------------------
  3056.  */
  3057. ENTRY void
  3058. VmMach_SetSegProt(segPtr, firstPage, lastPage, makeWriteable)
  3059.     register Vm_Segment        *segPtr;    /* Segment to change protection
  3060.                            for. */
  3061.     register int        firstPage;  /* First page to set protection
  3062.                          * for. */
  3063.     int                lastPage;   /* First page to set protection
  3064.                          * for. */
  3065.     Boolean            makeWriteable;/* TRUE => make the pages 
  3066.                            *     writable.
  3067.                            * FALSE => make readable only.*/
  3068. {
  3069.     register    VmMachPTE    pte;
  3070.     register    Address        virtAddr;
  3071.     register    VMMACH_SEG_NUM    *pmegNumPtr;
  3072.     register    PMEG        *pmegPtr;
  3073.     register    Boolean        skipSeg = FALSE;
  3074.     Boolean            nextSeg = TRUE;
  3075.     Address            tVirtAddr;
  3076.     Address            pageVirtAddr;
  3077.     int                i;
  3078.     int                oldContext;
  3079.  
  3080.     MASTER_LOCK(vmMachMutexPtr);
  3081.  
  3082.     pmegNumPtr = (VMMACH_SEG_NUM *)
  3083.         GetHardSegPtr(segPtr->machPtr, PageToSeg(firstPage)) - 1;
  3084.     virtAddr = (Address)(firstPage << VMMACH_PAGE_SHIFT);
  3085.     while (firstPage <= lastPage) {
  3086.     if (nextSeg) {
  3087.         pmegNumPtr++;
  3088.         if (*pmegNumPtr != VMMACH_INV_PMEG) {
  3089.         pmegPtr = &pmegArray[*pmegNumPtr];
  3090.         if (pmegPtr->pageCount != 0) {
  3091.             /* Flush this segment in all contexts */
  3092.             oldContext =  VmMachGetContextReg();
  3093.             for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  3094.             VmMachSetContextReg(i);
  3095.             VmMachFlushSegment(virtAddr);
  3096.             }
  3097.             VmMachSetContextReg(oldContext);
  3098.             VmMachSetSegMap(vmMachPTESegAddr, (int)*pmegNumPtr);
  3099.             skipSeg = FALSE;
  3100.         } else {
  3101.             skipSeg = TRUE;
  3102.         }
  3103.         } else {
  3104.         skipSeg = TRUE;
  3105.         }
  3106.         nextSeg = FALSE;
  3107.     }
  3108.     if (!skipSeg) {
  3109.         /*
  3110.          * Change the hardware page table.
  3111.          */
  3112.         tVirtAddr =
  3113.         ((unsigned int)virtAddr & VMMACH_PAGE_MASK) + vmMachPTESegAddr;
  3114.         for (i = 0; i < VMMACH_CLUSTER_SIZE; i++) {
  3115.         pageVirtAddr = tVirtAddr + i * VMMACH_PAGE_SIZE_INT;
  3116.         pte = VmMachGetPageMap(pageVirtAddr);
  3117.         if (pte & VMMACH_RESIDENT_BIT) {
  3118.             Vm_TracePTEChange    pteChange;
  3119.             if (vm_Tracing) {
  3120.             pteChange.changeType = VM_TRACE_SET_SEG_PROT;
  3121.             pteChange.segNum = segPtr->segNum;
  3122.             pteChange.pageNum = firstPage;
  3123.             pteChange.softPTE = FALSE;
  3124.             pteChange.beforePTE = pte;
  3125.             }
  3126.             pte &= ~VMMACH_PROTECTION_FIELD;
  3127.             pte |= makeWriteable ? VMMACH_URW_PROT : VMMACH_UR_PROT;
  3128.             if (vm_Tracing) {
  3129.             pteChange.afterPTE = pte;
  3130.             VmStoreTraceRec(VM_TRACE_PTE_CHANGE_REC,
  3131.                      sizeof(Vm_TracePTEChange),
  3132.                      (Address)&pteChange, TRUE);
  3133.             }
  3134. #ifdef sun4
  3135.             if (virtAddr >= vmStackEndAddr) {
  3136.             pte |= VMMACH_DONT_CACHE_BIT;
  3137.             } else {
  3138.             pte &= ~VMMACH_DONT_CACHE_BIT;
  3139.             }
  3140. #endif sun4
  3141.             VmMachSetPageMap(pageVirtAddr, pte);
  3142.         }
  3143.         }
  3144.         virtAddr += VMMACH_PAGE_SIZE;
  3145.         firstPage++;
  3146.         if (((unsigned int)virtAddr & VMMACH_PAGE_MASK) == 0) {
  3147.         nextSeg = TRUE;
  3148.         }
  3149.     } else {
  3150.         int    segNum;
  3151.  
  3152.         segNum = PageToSeg(firstPage) + 1;
  3153.         firstPage = SegToPage(segNum);
  3154.         virtAddr = (Address)(firstPage << VMMACH_PAGE_SHIFT);
  3155.         nextSeg = TRUE;
  3156.     }
  3157.     }
  3158.  
  3159.     MASTER_UNLOCK(vmMachMutexPtr);
  3160. }
  3161.  
  3162.  
  3163. /*
  3164.  *----------------------------------------------------------------------
  3165.  *
  3166.  * VmMach_SetPageProt --
  3167.  *
  3168.  *    Set the protection in hardware and software for the given virtual
  3169.  *    page.
  3170.  *
  3171.  * Results:
  3172.  *    None.
  3173.  *
  3174.  * Side effects:
  3175.  *    Page table may be modified for the segment.
  3176.  *
  3177.  *----------------------------------------------------------------------
  3178.  */
  3179. ENTRY void
  3180. VmMach_SetPageProt(virtAddrPtr, softPTE)
  3181.     register    Vm_VirtAddr    *virtAddrPtr;    /* The virtual page to set the
  3182.                          * protection for.*/
  3183.     Vm_PTE            softPTE;    /* Software pte. */
  3184. {
  3185.     register    VmMachPTE     hardPTE;
  3186.     register    VmMach_SegData    *machPtr;
  3187.     Address               virtAddr;
  3188.     int                pmegNum;
  3189.     int                i;
  3190.     Vm_TracePTEChange        pteChange;
  3191. #ifdef sun4
  3192.     Address            testVirtAddr;
  3193. #endif sun4
  3194.     int                j;
  3195.     int                oldContext;
  3196.  
  3197.     MASTER_LOCK(vmMachMutexPtr);
  3198.  
  3199.     machPtr = virtAddrPtr->segPtr->machPtr;
  3200.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  3201.         virtAddrPtr));
  3202.     if (pmegNum != VMMACH_INV_PMEG) {
  3203.     virtAddr = ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & 
  3204.             VMMACH_PAGE_MASK) + vmMachPTESegAddr;    
  3205. #ifdef sun4
  3206.     testVirtAddr = (Address) (virtAddrPtr->page << VMMACH_PAGE_SHIFT);
  3207. #endif sun4
  3208.     for (i = 0; 
  3209.          i < VMMACH_CLUSTER_SIZE; 
  3210.          i++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  3211.         hardPTE = VmMachReadPTE(pmegNum, virtAddr);
  3212.         if (vm_Tracing) {
  3213.         pteChange.changeType = VM_TRACE_SET_PAGE_PROT;
  3214.         pteChange.segNum = virtAddrPtr->segPtr->segNum;
  3215.         pteChange.pageNum = virtAddrPtr->page;
  3216.         pteChange.softPTE = FALSE;
  3217.         pteChange.beforePTE = hardPTE;
  3218.         }
  3219.         hardPTE &= ~VMMACH_PROTECTION_FIELD;
  3220.         hardPTE |= (softPTE & (VM_COW_BIT | VM_READ_ONLY_PROT)) ? 
  3221.                     VMMACH_UR_PROT : VMMACH_URW_PROT;
  3222.         if (vm_Tracing) {
  3223.         pteChange.afterPTE = hardPTE;
  3224.         VmStoreTraceRec(VM_TRACE_PTE_CHANGE_REC,
  3225.                  sizeof(Vm_TracePTEChange), 
  3226.                  (Address)&pteChange, TRUE);
  3227.         }
  3228. #ifdef sun4
  3229.         if (testVirtAddr >= vmStackEndAddr) {
  3230.         hardPTE |= VMMACH_DONT_CACHE_BIT;
  3231.         } else {
  3232.         hardPTE &= ~VMMACH_DONT_CACHE_BIT;
  3233.         }
  3234. #endif sun4
  3235.         /* Flush this page in all contexts */
  3236.         oldContext =  VmMachGetContextReg();
  3237.         for (j = 0; j < VMMACH_NUM_CONTEXTS; j++) {
  3238.         VmMachSetContextReg(j);
  3239.         VmMachFlushPage(testVirtAddr);
  3240.         }
  3241.         VmMachSetContextReg(oldContext);
  3242.         VmMachWritePTE(pmegNum, virtAddr, hardPTE);
  3243.     }
  3244.     }
  3245.  
  3246.     MASTER_UNLOCK(vmMachMutexPtr);
  3247. }
  3248.  
  3249.  
  3250. /*
  3251.  * ----------------------------------------------------------------------------
  3252.  *
  3253.  * VmMach_AllocCheck --
  3254.  *
  3255.  *      Determine if this page can be reallocated.  A page can be reallocated
  3256.  *    if it has not been referenced or modified.
  3257.  *  
  3258.  * Results:
  3259.  *      None.
  3260.  *
  3261.  * Side effects:
  3262.  *      The given page will be invalidated in the hardware if it has not
  3263.  *    been referenced and *refPtr and *modPtr will have the hardware 
  3264.  *    reference and modify bits or'd in.
  3265.  *
  3266.  * ----------------------------------------------------------------------------
  3267.  */
  3268. ENTRY void
  3269. VmMach_AllocCheck(virtAddrPtr, virtFrameNum, refPtr, modPtr)
  3270.     register    Vm_VirtAddr    *virtAddrPtr;
  3271.     unsigned    int        virtFrameNum;
  3272.     register    Boolean        *refPtr;
  3273.     register    Boolean        *modPtr;
  3274. {
  3275.     register VmMach_SegData    *machPtr;
  3276.     register VmMachPTE         hardPTE;  
  3277.     int                pmegNum; 
  3278.     Address            virtAddr;
  3279.     int                i;
  3280.     int                origMod;
  3281.  
  3282.     MASTER_LOCK(vmMachMutexPtr);
  3283.  
  3284.     origMod = *modPtr;
  3285.  
  3286.     *refPtr |= refModMap[virtFrameNum] & VMMACH_REFERENCED_BIT;
  3287.     *modPtr = refModMap[virtFrameNum] & VMMACH_MODIFIED_BIT;
  3288.     if (!*refPtr || !*modPtr) {
  3289.     machPtr = virtAddrPtr->segPtr->machPtr;
  3290.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  3291.         virtAddrPtr));
  3292.     if (pmegNum != VMMACH_INV_PMEG) {
  3293.         hardPTE = 0;
  3294.         virtAddr = 
  3295.         ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & VMMACH_PAGE_MASK) + 
  3296.             vmMachPTESegAddr;
  3297.         for (i = 0; i < VMMACH_CLUSTER_SIZE; i++ ) {
  3298.         hardPTE |= VmMachReadPTE(pmegNum, 
  3299.                     virtAddr + i * VMMACH_PAGE_SIZE_INT);
  3300.         }
  3301.         *refPtr |= hardPTE & VMMACH_REFERENCED_BIT;
  3302.         *modPtr |= hardPTE & VMMACH_MODIFIED_BIT;
  3303.     }
  3304.     }
  3305.     if (!*refPtr) {
  3306.     /*
  3307.      * Invalidate the page so that it will force a fault if it is
  3308.      * referenced.  Since our caller has blocked all faults on this
  3309.      * page, by invalidating it we can guarantee that the reference and
  3310.      * modify information that we are returning will be valid until
  3311.      * our caller reenables faults on this page.
  3312.      */
  3313.     PageInvalidate(virtAddrPtr, virtFrameNum, FALSE);
  3314.  
  3315.     if (origMod && !*modPtr) {
  3316.         /*
  3317.          * This page had the modify bit set in software but not in
  3318.          * hardware.
  3319.          */
  3320.         vmStat.notHardModPages++;
  3321.     }
  3322.     }
  3323.     *modPtr |= origMod;
  3324.  
  3325.     MASTER_UNLOCK(vmMachMutexPtr);
  3326.  
  3327. }
  3328.  
  3329.  
  3330. /*
  3331.  * ----------------------------------------------------------------------------
  3332.  *
  3333.  * VmMach_GetRefModBits --
  3334.  *
  3335.  *      Pull the reference and modified bits out of hardware.
  3336.  *  
  3337.  * Results:
  3338.  *      None.
  3339.  *
  3340.  * Side effects:
  3341.  *      
  3342.  *
  3343.  * ----------------------------------------------------------------------------
  3344.  */
  3345. ENTRY void
  3346. VmMach_GetRefModBits(virtAddrPtr, virtFrameNum, refPtr, modPtr)
  3347.     register    Vm_VirtAddr    *virtAddrPtr;
  3348.     unsigned    int        virtFrameNum;
  3349.     register    Boolean        *refPtr;
  3350.     register    Boolean        *modPtr;
  3351. {
  3352.     register VmMach_SegData    *machPtr;
  3353.     register VmMachPTE         hardPTE;  
  3354.     int                pmegNum; 
  3355.     Address            virtAddr;
  3356.     int                i;
  3357.  
  3358.     MASTER_LOCK(vmMachMutexPtr);
  3359.  
  3360.     *refPtr = refModMap[virtFrameNum] & VMMACH_REFERENCED_BIT;
  3361.     *modPtr = refModMap[virtFrameNum] & VMMACH_MODIFIED_BIT;
  3362.     if (!*refPtr || !*modPtr) {
  3363.     machPtr = virtAddrPtr->segPtr->machPtr;
  3364.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  3365.         virtAddrPtr));
  3366.     if (pmegNum != VMMACH_INV_PMEG) {
  3367.         hardPTE = 0;
  3368.         virtAddr = 
  3369.         ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & VMMACH_PAGE_MASK) + 
  3370.             vmMachPTESegAddr;
  3371.         for (i = 0; i < VMMACH_CLUSTER_SIZE; i++ ) {
  3372.         hardPTE |= VmMachReadPTE(pmegNum, 
  3373.                     virtAddr + i * VMMACH_PAGE_SIZE_INT);
  3374.         }
  3375.         if (!*refPtr) {
  3376.         *refPtr = hardPTE & VMMACH_REFERENCED_BIT;
  3377.         }
  3378.         if (!*modPtr) {
  3379.         *modPtr = hardPTE & VMMACH_MODIFIED_BIT;
  3380.         }
  3381.     }
  3382.     }
  3383.  
  3384.     MASTER_UNLOCK(vmMachMutexPtr);
  3385.  
  3386. }
  3387.  
  3388.  
  3389. /*
  3390.  * ----------------------------------------------------------------------------
  3391.  *
  3392.  * VmMach_ClearRefBit --
  3393.  *
  3394.  *      Clear the reference bit at the given virtual address.
  3395.  *
  3396.  * Results:
  3397.  *      None.
  3398.  *
  3399.  * Side effects:
  3400.  *      Hardware reference bit cleared.
  3401.  *
  3402.  * ----------------------------------------------------------------------------
  3403.  */
  3404. ENTRY void
  3405. VmMach_ClearRefBit(virtAddrPtr, virtFrameNum)
  3406.     register    Vm_VirtAddr    *virtAddrPtr;
  3407.     unsigned     int        virtFrameNum;
  3408. {
  3409.     register    VmMach_SegData    *machPtr;
  3410.     int                pmegNum;
  3411.     Address            virtAddr;
  3412.     int                i;
  3413.     VmMachPTE            pte;
  3414.     Vm_TracePTEChange        pteChange;
  3415.  
  3416.     MASTER_LOCK(vmMachMutexPtr);
  3417.  
  3418.     refModMap[virtFrameNum] &= ~VMMACH_REFERENCED_BIT;
  3419.     machPtr = virtAddrPtr->segPtr->machPtr;
  3420.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  3421.         virtAddrPtr));
  3422.     if (pmegNum != VMMACH_INV_PMEG) {
  3423.     virtAddr = ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & 
  3424.             VMMACH_PAGE_MASK) + vmMachPTESegAddr;
  3425.     for (i = 0; 
  3426.          i < VMMACH_CLUSTER_SIZE;
  3427.          i++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  3428.         pte = VmMachReadPTE(pmegNum, virtAddr);
  3429.         if (vm_Tracing) {
  3430.         pteChange.changeType = VM_TRACE_CLEAR_REF_BIT;
  3431.         pteChange.segNum = virtAddrPtr->segPtr->segNum;
  3432.         pteChange.pageNum = virtAddrPtr->page;
  3433.         pteChange.softPTE = FALSE;
  3434.         pteChange.beforePTE = pte;
  3435.         pteChange.afterPTE = pte & ~VMMACH_REFERENCED_BIT;
  3436.         VmStoreTraceRec(VM_TRACE_PTE_CHANGE_REC,
  3437.                  sizeof(Vm_TracePTEChange), 
  3438.                  (Address)&pteChange, TRUE);
  3439.         }
  3440.         pte &= ~VMMACH_REFERENCED_BIT;
  3441.         VmMachWritePTE(pmegNum, virtAddr, pte);
  3442.     }
  3443.     }
  3444.  
  3445.     MASTER_UNLOCK(vmMachMutexPtr);
  3446. }
  3447.  
  3448.  
  3449. /*
  3450.  * ----------------------------------------------------------------------------
  3451.  *
  3452.  * VmMach_ClearModBit --
  3453.  *
  3454.  *      Clear the modified bit at the given virtual address.
  3455.  *
  3456.  * Results:
  3457.  *      None.
  3458.  *
  3459.  * Side effects:
  3460.  *      Hardware modified bit cleared.
  3461.  *
  3462.  * ----------------------------------------------------------------------------
  3463.  */
  3464. ENTRY void
  3465. VmMach_ClearModBit(virtAddrPtr, virtFrameNum)
  3466.     register    Vm_VirtAddr    *virtAddrPtr;
  3467.     unsigned    int        virtFrameNum;
  3468. {
  3469.     register    VmMach_SegData    *machPtr;
  3470.     int                pmegNum;
  3471.     Address            virtAddr;
  3472.     int                i;
  3473.     Vm_PTE            pte;
  3474.     Vm_TracePTEChange        pteChange;
  3475.  
  3476.     MASTER_LOCK(vmMachMutexPtr);
  3477.  
  3478.     refModMap[virtFrameNum] &= ~VMMACH_MODIFIED_BIT;
  3479.     machPtr = virtAddrPtr->segPtr->machPtr;
  3480.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  3481.         virtAddrPtr));
  3482.     if (pmegNum != VMMACH_INV_PMEG) {
  3483.     virtAddr = ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & 
  3484.             VMMACH_PAGE_MASK) + vmMachPTESegAddr;
  3485.     for (i = 0; 
  3486.          i < VMMACH_CLUSTER_SIZE; 
  3487.          i++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  3488.         pte = VmMachReadPTE(pmegNum, virtAddr);
  3489.         if (vm_Tracing) {
  3490.         pteChange.changeType = VM_TRACE_CLEAR_MOD_BIT;
  3491.         pteChange.segNum = virtAddrPtr->segPtr->segNum;
  3492.         pteChange.pageNum = virtAddrPtr->page;
  3493.         pteChange.softPTE = FALSE;
  3494.         pteChange.beforePTE = pte;
  3495.         pteChange.afterPTE = pte & ~VMMACH_MODIFIED_BIT;
  3496.         VmStoreTraceRec(VM_TRACE_PTE_CHANGE_REC,
  3497.                 sizeof(Vm_TracePTEChange), 
  3498.                 (Address)&pteChange, TRUE);
  3499.         }
  3500.         pte &= ~VMMACH_MODIFIED_BIT;
  3501.         VmMachWritePTE(pmegNum, virtAddr, pte);
  3502.     }
  3503.     }
  3504.  
  3505.     MASTER_UNLOCK(vmMachMutexPtr);
  3506. }
  3507.  
  3508.  
  3509. /*
  3510.  * ----------------------------------------------------------------------------
  3511.  *
  3512.  * VmMach_PageValidate --
  3513.  *
  3514.  *      Validate a page for the given virtual address.  It is assumed that when
  3515.  *      this routine is called that the user context register contains the
  3516.  *    context in which the page will be validated.
  3517.  *
  3518.  * Results:
  3519.  *      None.
  3520.  *
  3521.  * Side effects:
  3522.  *      The page table and hardware segment tables associated with the segment
  3523.  *      are modified to validate the page.
  3524.  *
  3525.  * ----------------------------------------------------------------------------
  3526.  */
  3527.  
  3528. ENTRY void
  3529. VmMach_PageValidate(virtAddrPtr, pte) 
  3530.     register    Vm_VirtAddr    *virtAddrPtr;
  3531.     Vm_PTE            pte;
  3532. {
  3533.     register  Vm_Segment    *segPtr;
  3534.     register  VMMACH_SEG_NUM    *segTablePtr;
  3535.     register  PMEG        *pmegPtr;
  3536.     register  int        hardSeg;
  3537.     register  VmMachPTE        hardPTE;
  3538.     register  VmMachPTE        tHardPTE;
  3539.     struct    PMEGseg        *pmegSegPtr;
  3540.     Vm_PTE    *ptePtr;
  3541.     Address    addr;
  3542.     Boolean    reLoadPMEG;      /* TRUE if we had to reload this PMEG. */
  3543.     int        i;
  3544.     int        tmpSegNum;
  3545.  
  3546.     MASTER_LOCK(vmMachMutexPtr);
  3547.  
  3548.     segPtr = virtAddrPtr->segPtr;
  3549.     addr = (Address) (virtAddrPtr->page << VMMACH_PAGE_SHIFT);
  3550. #ifdef sun4
  3551.     if (!VMMACH_ADDR_CHECK(addr)) {
  3552.     panic("VmMach_PageValidate: virt addr 0x%x falls into illegal range!\n",
  3553.         addr);
  3554.     }
  3555. #endif sun4
  3556.  
  3557.     /*
  3558.      * Find out the hardware segment that has to be mapped.
  3559.      * If this is a mapping segment, this gives us the seg num
  3560.      * for the segment in the other process and the segPtr is the mapSegPtr
  3561.      * which is set to the segPtr of the other process.
  3562.      */
  3563.  
  3564.     hardSeg = PageToOffSeg(virtAddrPtr->page, virtAddrPtr);
  3565.  
  3566.     segTablePtr = (VMMACH_SEG_NUM *) GetHardSegPtr(segPtr->machPtr, hardSeg);
  3567.     pmegPtr = &pmegArray[*segTablePtr]; /* Software seg's pmeg. */
  3568.     tmpSegNum = VmMachGetSegMap(addr);  /* Hardware seg's pmeg. */
  3569.     if (tmpSegNum != VMMACH_INV_PMEG && tmpSegNum != (int)*segTablePtr) {
  3570.     if (!(Proc_GetCurrentProc()->vmPtr->vmFlags & VM_COPY_IN_PROGRESS)) {
  3571.         if (*segTablePtr != VMMACH_INV_PMEG) {
  3572.         if (debugVmStubs) {
  3573.             printf("VmMach_PageValidate: multiple pmegs used!\n");
  3574.             printf(" seg = %d, pmeg %d,%d, proc=%x %s\n",
  3575.                 segPtr->segNum, *segTablePtr, tmpSegNum,
  3576.                 Proc_GetCurrentProc()->processID,
  3577.                 Proc_GetCurrentProc()->argString);
  3578.             printf("  old seg = %x\n",
  3579.                 pmegArray[tmpSegNum].segInfo.segPtr->segNum);
  3580.             printf("Freeing pmeg %d\n", *segTablePtr);
  3581.         }
  3582.         PMEGFree(*segTablePtr);
  3583.         }
  3584.         if (debugVmStubs) {
  3585.         printf("Multiple segs in hard segment: seg = %d, pmeg %d,%d, proc=%x %s\n",
  3586.             segPtr->segNum, *segTablePtr, tmpSegNum,
  3587.             Proc_GetCurrentProc()->processID,
  3588.             Proc_GetCurrentProc()->argString);
  3589.         }
  3590.  
  3591.         *segTablePtr = (VMMACH_SEG_NUM) tmpSegNum;
  3592.         pmegPtr = &pmegArray[*segTablePtr];
  3593.         pmegSegPtr = (struct PMEGseg *)malloc(sizeof(struct PMEGseg));
  3594.         pmegSegPtr->nextLink = pmegPtr->segInfo.nextLink;
  3595.         pmegPtr->segInfo.nextLink = pmegSegPtr;
  3596.         pmegSegPtr->segPtr = virtAddrPtr->segPtr;
  3597.         pmegSegPtr->hardSegNum = hardSeg;
  3598.     }
  3599.     }
  3600.  
  3601.     reLoadPMEG = FALSE;
  3602.     if (*segTablePtr == VMMACH_INV_PMEG) {
  3603.     int flags;
  3604.     /*
  3605.      * If there is not already a pmeg for this hardware segment, then get
  3606.      * one and initialize it.  If this is for the kernel then make
  3607.      * sure that the pmeg cannot be taken away from the kernel.
  3608.      * We make an exception for PMEGs allocated only for the block cache.
  3609.      * If we fault on kernel pmeg we reload all the mappings for the
  3610.      * pmeg because we can't tolerate "quick" faults in some places in the
  3611.      * kernel.
  3612.      */
  3613.     flags = 0;
  3614.     if (segPtr == vm_SysSegPtr) {
  3615.        if (IN_FILE_CACHE_SEG(addr) && vmMachCanStealFileCachePmegs) {
  3616.           /*
  3617.            * In block cache virtual addresses.
  3618.            */
  3619.           reLoadPMEG = TRUE;
  3620.        } else {
  3621.           /*
  3622.            * Normal kernel PMEGs must still be wired.
  3623.            */
  3624.           flags = PMEG_DONT_ALLOC;
  3625.        }
  3626.     }
  3627.         *segTablePtr = PMEGGet(segPtr, hardSeg, flags);
  3628.     pmegPtr = &pmegArray[*segTablePtr];
  3629.     } else {
  3630.     pmegPtr = &pmegArray[*segTablePtr];
  3631.     if (pmegPtr->pageCount == 0) {
  3632.         /*
  3633.          * We are using a PMEG that had a pagecount of 0.  In this case
  3634.          * it was put onto the end of the free pmeg list in anticipation
  3635.          * of someone stealing this empty pmeg.  Now we have to move
  3636.          * it off of the free list.
  3637.          */
  3638. #ifndef CLEAN
  3639.         VmCheckListIntegrity((List_Links *)pmegPtr);
  3640. #endif
  3641.         if (pmegPtr->flags & PMEG_DONT_ALLOC) {
  3642.         List_Remove((List_Links *)pmegPtr);
  3643.         } else {
  3644.         List_Move((List_Links *)pmegPtr, LIST_ATREAR(pmegInuseList));
  3645. #ifndef CLEAN
  3646.         VmCheckListIntegrity((List_Links *)pmegPtr);
  3647. #endif
  3648.         }
  3649.     }
  3650.     }
  3651.     hardPTE = VMMACH_RESIDENT_BIT | VirtToPhysPage(Vm_GetPageFrame(pte));
  3652. #ifdef sun4
  3653.     if (addr < (Address) VMMACH_DEV_START_ADDR) {
  3654.         hardPTE &= ~VMMACH_DONT_CACHE_BIT;
  3655.     } else {
  3656.     hardPTE |= VMMACH_DONT_CACHE_BIT;
  3657.     }
  3658. #endif /* sun4 */
  3659.     if (segPtr == vm_SysSegPtr) {
  3660.     int    oldContext;
  3661.     /*
  3662.      * Have to propagate the PMEG to all contexts.
  3663.      */
  3664.     oldContext = VmMachGetContextReg();
  3665.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  3666.         VmMachSetContextReg(i);
  3667.         VmMachSetSegMap(addr, (int)*segTablePtr);
  3668.     }
  3669.     VmMachSetContextReg(oldContext);
  3670.     hardPTE |= VMMACH_KRW_PROT;
  3671.     } else {
  3672.     Proc_ControlBlock    *procPtr;
  3673.     VmProcLink        *procLinkPtr;
  3674.     VmMach_Context      *contextPtr;
  3675.  
  3676.     procPtr = Proc_GetCurrentProc();
  3677.     if (virtAddrPtr->flags & USING_MAPPED_SEG) {
  3678.         addr = (Address) (VMMACH_MAP_SEG_ADDR + 
  3679.                 ((unsigned int)addr & (VMMACH_SEG_SIZE - 1)));
  3680.         /* PUT IT IN SOFTWARE OF MAP AREA FOR PROCESS */
  3681.         procPtr->vmPtr->machPtr->contextPtr->map[MAP_SEG_NUM] =
  3682.             *segTablePtr;
  3683.     } else{
  3684.         /* update it for regular seg num */
  3685.         procPtr->vmPtr->machPtr->contextPtr->map[hardSeg] = *segTablePtr;
  3686.     }
  3687.     VmMachSetSegMap(addr, (int)*segTablePtr);
  3688.  
  3689.         if (segPtr != (Vm_Segment *) NIL) {
  3690. #ifndef CLEAN
  3691.         VmCheckListIntegrity((List_Links *)segPtr->procList);
  3692. #endif
  3693.             LIST_FORALL(segPtr->procList, (List_Links *)procLinkPtr) {
  3694.         if (procLinkPtr->procPtr->vmPtr != (Vm_ProcInfo *) NIL &&
  3695.             procLinkPtr->procPtr->vmPtr->machPtr !=
  3696.             (VmMach_ProcData *) NIL &&
  3697.             (contextPtr =
  3698.             procLinkPtr->procPtr->vmPtr->machPtr->contextPtr) !=
  3699.             (VmMach_Context *) NIL) {
  3700.             contextPtr->map[hardSeg] = *segTablePtr;
  3701.         }
  3702.         }
  3703.     }
  3704.  
  3705.     if ((pte & (VM_COW_BIT | VM_READ_ONLY_PROT)) ||
  3706.         (virtAddrPtr->flags & VM_READONLY_SEG)) {
  3707.         hardPTE |= VMMACH_UR_PROT;
  3708.     } else {
  3709.         hardPTE |= VMMACH_URW_PROT;
  3710.     }
  3711.     }
  3712.     tHardPTE = VmMachGetPageMap(addr);
  3713.     if (tHardPTE & VMMACH_RESIDENT_BIT) {
  3714.     hardPTE |= tHardPTE & (VMMACH_REFERENCED_BIT | VMMACH_MODIFIED_BIT);
  3715.     for (i = 1; i < VMMACH_CLUSTER_SIZE; i++ ) {
  3716.         hardPTE |= VmMachGetPageMap(addr + i * VMMACH_PAGE_SIZE_INT) & 
  3717.                 (VMMACH_REFERENCED_BIT | VMMACH_MODIFIED_BIT);
  3718.     }
  3719.     } else {
  3720.     if (*segTablePtr == VMMACH_INV_PMEG) {
  3721.         panic("Invalid pmeg\n");
  3722.     }
  3723.     pmegArray[*segTablePtr].pageCount++;
  3724.     }
  3725.     if (vm_Tracing) {
  3726.     Vm_TracePTEChange    pteChange;
  3727.  
  3728.     pteChange.changeType = VM_TRACE_VALIDATE_PAGE;
  3729.     pteChange.segNum = segPtr->segNum;
  3730.     pteChange.pageNum = virtAddrPtr->page;
  3731.     pteChange.softPTE = FALSE;
  3732.     if (tHardPTE & VMMACH_RESIDENT_BIT) {
  3733.         pteChange.beforePTE = tHardPTE;
  3734.     } else {
  3735.         pteChange.beforePTE = 0;
  3736.     }
  3737.     pteChange.afterPTE = hardPTE;
  3738.     VmStoreTraceRec(VM_TRACE_PTE_CHANGE_REC,
  3739.             sizeof(Vm_TracePTEChange), 
  3740.             (Address)&pteChange, TRUE);
  3741.     }
  3742.  
  3743.     /* Flush something? */
  3744.     SET_ALL_PAGE_MAP(addr, hardPTE);
  3745.     if (reLoadPMEG) {
  3746.     /*
  3747.      * Reload all pte's for this pmeg.
  3748.      */
  3749.     unsigned int a = (hardSeg << VMMACH_SEG_SHIFT);
  3750.     int    pageCount = 0;
  3751.     for (i = 0; i < VMMACH_NUM_PAGES_PER_SEG_INT; i++ ) { 
  3752.         ptePtr = VmGetPTEPtr(vm_SysSegPtr, (a >> VMMACH_PAGE_SHIFT));
  3753.         if ((*ptePtr & VM_PHYS_RES_BIT)) {
  3754.         hardPTE = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | 
  3755.                 VirtToPhysPage(Vm_GetPageFrame(*ptePtr));
  3756.         SET_ALL_PAGE_MAP(a, hardPTE);
  3757.         pageCount++;
  3758.          }
  3759.          a += VMMACH_PAGE_SIZE_INT;
  3760.     }
  3761.     if (pmegPtr-pmegArray == VMMACH_INV_PMEG) {
  3762.         panic("Invalid pmeg\n");
  3763.     }
  3764.     pmegPtr->pageCount = pageCount;
  3765.     }
  3766.  
  3767.     MASTER_UNLOCK(vmMachMutexPtr);
  3768. }
  3769.  
  3770.  
  3771. /*
  3772.  * ----------------------------------------------------------------------------
  3773.  *
  3774.  * PageInvalidate --
  3775.  *
  3776.  *      Invalidate a page for the given segment.  
  3777.  *
  3778.  * Results:
  3779.  *      None.
  3780.  *
  3781.  * Side effects:
  3782.  *      The page table and hardware segment tables associated with the segment
  3783.  *      are modified to invalidate the page.
  3784.  *
  3785.  * ----------------------------------------------------------------------------
  3786.  */
  3787. static void
  3788. PageInvalidate(virtAddrPtr, virtPage, segDeletion) 
  3789.     register    Vm_VirtAddr    *virtAddrPtr;
  3790.     unsigned     int        virtPage;
  3791.     Boolean            segDeletion;
  3792. {
  3793.     register VmMach_SegData    *machPtr;
  3794.     register PMEG        *pmegPtr;
  3795.     VmMachPTE            hardPTE;
  3796.     int                pmegNum;
  3797.     Address            addr;
  3798.     int                i;
  3799.     Vm_TracePTEChange        pteChange;
  3800.     Address            testVirtAddr;
  3801.     VmProcLink              *flushProcLinkPtr;
  3802.     Vm_Segment              *flushSegPtr;
  3803.     Vm_ProcInfo             *flushVmPtr;
  3804.     VmMach_ProcData         *flushMachPtr;
  3805.     VmMach_Context          *flushContextPtr;
  3806.     unsigned int            flushContext;
  3807.     unsigned int            oldContext;
  3808.  
  3809.     refModMap[virtPage] = 0;
  3810.     if (segDeletion) {
  3811.     return;
  3812.     }
  3813.     machPtr = virtAddrPtr->segPtr->machPtr;
  3814.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  3815.         virtAddrPtr));
  3816.     if (pmegNum == VMMACH_INV_PMEG) {
  3817.     return;
  3818.     }
  3819.     testVirtAddr = (Address) (virtAddrPtr->page << VMMACH_PAGE_SHIFT);
  3820.     addr = ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) &
  3821.                 VMMACH_PAGE_MASK) + vmMachPTESegAddr;
  3822. #ifdef sun4
  3823.     if (!VMMACH_ADDR_CHECK(addr)) {
  3824.     panic("PageInvalidate: virt addr 0x%x falls into illegal range!\n",
  3825.         addr);
  3826.     }
  3827. #endif sun4
  3828.     hardPTE = VmMachReadPTE(pmegNum, addr);
  3829.     if (vm_Tracing) {
  3830.     pteChange.changeType = VM_TRACE_INVALIDATE_PAGE;
  3831.     pteChange.segNum = virtAddrPtr->segPtr->segNum;
  3832.     pteChange.pageNum = virtAddrPtr->page;
  3833.     pteChange.softPTE = FALSE;
  3834.     pteChange.beforePTE = hardPTE;
  3835.     pteChange.afterPTE = 0;
  3836.     VmStoreTraceRec(VM_TRACE_PTE_CHANGE_REC, sizeof(Vm_TracePTEChange),
  3837.             (Address)&pteChange, TRUE);
  3838.     }
  3839.     /*
  3840.      * Invalidate the page table entry.  There's no need to flush the page if
  3841.      * the invalidation is due to segment deletion, since the whole segment
  3842.      * will already have been flushed.  Flush the page in the context in which
  3843.      * it was validated.
  3844.      */
  3845.     if (!segDeletion) {
  3846.     int    flushedP = FALSE;
  3847.  
  3848.         flushSegPtr = virtAddrPtr->segPtr;
  3849.         if (flushSegPtr != (Vm_Segment *) NIL) {
  3850. #ifndef CLEAN
  3851.         VmCheckListIntegrity((List_Links *)flushSegPtr->procList);
  3852. #endif
  3853.             LIST_FORALL(flushSegPtr->procList, (List_Links *)flushProcLinkPtr) {
  3854.                 flushVmPtr = flushProcLinkPtr->procPtr->vmPtr;
  3855.                 if (flushVmPtr != (Vm_ProcInfo *) NIL) {
  3856.                     flushMachPtr = flushVmPtr->machPtr;
  3857.                     if (flushMachPtr != (VmMach_ProcData *) NIL) {
  3858.                         flushContextPtr = flushMachPtr->contextPtr;
  3859.                         if (flushContextPtr != (VmMach_Context *) NIL) {
  3860.                             flushContext = flushContextPtr->context;
  3861.                             /* save old context */
  3862.                             oldContext = VmMachGetContextReg();
  3863.                             /* move to page's context */
  3864.                             VmMachSetContextReg((int)flushContext);
  3865.                             /* flush page in its context */
  3866.                             VmMachFlushPage(testVirtAddr);
  3867.                             /* back to old context */
  3868.                             VmMachSetContextReg((int)oldContext);
  3869.                 flushedP = TRUE;
  3870.                         }
  3871.                     }
  3872.                 }
  3873.             }
  3874.         }
  3875.     if (!flushedP) {
  3876.         VmMachFlushPage(testVirtAddr);
  3877.     }
  3878.     }
  3879.     for (i = 0; i < VMMACH_CLUSTER_SIZE; i++, addr += VMMACH_PAGE_SIZE_INT) {
  3880.     VmMachWritePTE(pmegNum, addr, (VmMachPTE)0);
  3881.     }
  3882.     pmegPtr = &pmegArray[pmegNum];
  3883.     if (hardPTE & VMMACH_RESIDENT_BIT) {
  3884.     pmegPtr->pageCount--;
  3885.     if (pmegPtr->pageCount == 0) {
  3886.         /*
  3887.          * When the pageCount goes to zero, the pmeg is put onto the end
  3888.          * of the free list so that it can get freed if someone else
  3889.          * needs a pmeg.  It isn't freed here because there is a fair
  3890.          * amount of overhead when freeing a pmeg so its best to keep
  3891.          * it around in case it is needed again.
  3892.          */
  3893.         if (pmegPtr->flags & PMEG_DONT_ALLOC) {
  3894.         List_Insert((List_Links *)pmegPtr, 
  3895.                 LIST_ATREAR(pmegFreeList));
  3896.         } else {
  3897.         List_Move((List_Links *)pmegPtr, 
  3898.               LIST_ATREAR(pmegFreeList));
  3899.         }
  3900. #ifndef CLEAN
  3901.         VmCheckListIntegrity((List_Links *)pmegPtr);
  3902. #endif
  3903.     }
  3904.     }
  3905. }
  3906.  
  3907.  
  3908.  
  3909. /*
  3910.  * ----------------------------------------------------------------------------
  3911.  *
  3912.  * VmMach_PageInvalidate --
  3913.  *
  3914.  *      Invalidate a page for the given segment.  
  3915.  *
  3916.  * Results:
  3917.  *      None.
  3918.  *
  3919.  * Side effects:
  3920.  *      The page table and hardware segment tables associated with the segment
  3921.  *      are modified to invalidate the page.
  3922.  *
  3923.  * ----------------------------------------------------------------------------
  3924.  */
  3925. ENTRY void
  3926. VmMach_PageInvalidate(virtAddrPtr, virtPage, segDeletion) 
  3927.     register    Vm_VirtAddr    *virtAddrPtr;
  3928.     unsigned     int        virtPage;
  3929.     Boolean            segDeletion;
  3930. {
  3931.     MASTER_LOCK(vmMachMutexPtr);
  3932.  
  3933.     PageInvalidate(virtAddrPtr, virtPage, segDeletion);
  3934.  
  3935.     MASTER_UNLOCK(vmMachMutexPtr);
  3936. }
  3937.  
  3938.  
  3939. /*
  3940.  *----------------------------------------------------------------------
  3941.  *
  3942.  * VmMach_PinUserPages --
  3943.  *
  3944.  *    Force a user page to be resident in memory.
  3945.  *
  3946.  * Results:
  3947.  *    None.
  3948.  *
  3949.  * Side effects:
  3950.  *    None.
  3951.  *
  3952.  *----------------------------------------------------------------------
  3953.  */
  3954. /*ARGSUSED*/
  3955. void
  3956. VmMach_PinUserPages(mapType, virtAddrPtr, lastPage)
  3957.     int        mapType;
  3958.     Vm_VirtAddr    *virtAddrPtr;
  3959.     int        lastPage;
  3960. {
  3961.     int                *intPtr;
  3962.     int                dummy;
  3963.     register VmMach_SegData    *machPtr;
  3964.     register int        firstSeg;
  3965.     register int        lastSeg;
  3966.  
  3967.     machPtr = virtAddrPtr->segPtr->machPtr;
  3968.  
  3969.     firstSeg = PageToOffSeg(virtAddrPtr->page, virtAddrPtr);
  3970.     lastSeg = PageToOffSeg(lastPage, virtAddrPtr);
  3971.     /*
  3972.      * Lock down the PMEG behind the first segment.
  3973.      */
  3974.     intPtr = (int *) (virtAddrPtr->page << VMMACH_PAGE_SHIFT);
  3975.     while (!PMEGLock(machPtr, firstSeg)) {
  3976.     /*
  3977.      * Touch the page to bring it into memory.  We know that we can
  3978.      * safely touch it because we wouldn't have been called if these
  3979.      * weren't good addresses.
  3980.      */
  3981.     dummy = *intPtr;
  3982.     }
  3983.     /*
  3984.      * Lock down the rest of the segments.
  3985.      */
  3986.     for (firstSeg++; firstSeg <= lastSeg; firstSeg++) {
  3987.     intPtr = (int *)(firstSeg << VMMACH_SEG_SHIFT);
  3988.     while (!PMEGLock(machPtr, firstSeg)) {
  3989.         dummy = *intPtr;
  3990.     }
  3991.     }
  3992. #ifdef lint
  3993.     dummy = dummy;
  3994. #endif
  3995. }
  3996.  
  3997.  
  3998. /*
  3999.  *----------------------------------------------------------------------
  4000.  *
  4001.  * VmMach_UnpinUserPages --
  4002.  *
  4003.  *    Allow a page that was pinned to be unpinned.
  4004.  *
  4005.  * Results:
  4006.  *    None.
  4007.  *
  4008.  * Side effects:
  4009.  *    None.
  4010.  *
  4011.  *----------------------------------------------------------------------
  4012.  */
  4013. ENTRY void
  4014. VmMach_UnpinUserPages(virtAddrPtr, lastPage)
  4015.     Vm_VirtAddr    *virtAddrPtr;
  4016.     int        lastPage;
  4017. {
  4018.     register int    firstSeg;
  4019.     register int    lastSeg;
  4020.     int            pmegNum;
  4021.     register VmMach_SegData    *machPtr;
  4022.  
  4023.     MASTER_LOCK(vmMachMutexPtr);
  4024.  
  4025.     machPtr = virtAddrPtr->segPtr->machPtr;
  4026.     firstSeg = PageToOffSeg(virtAddrPtr->page, virtAddrPtr);
  4027.     lastSeg = PageToOffSeg(lastPage, virtAddrPtr);
  4028.     for (; firstSeg <= lastSeg; firstSeg++) {
  4029.     pmegNum = *GetHardSegPtr(machPtr, firstSeg);
  4030.     if (pmegNum == VMMACH_INV_PMEG) {
  4031.         MASTER_UNLOCK(vmMachMutexPtr);
  4032.         panic("Pinned PMEG invalid???\n");
  4033.         return;
  4034.     }
  4035.     pmegArray[pmegNum].lockCount--;
  4036.     }
  4037.  
  4038.     MASTER_UNLOCK(vmMachMutexPtr);
  4039. }
  4040.  
  4041.  
  4042. /*
  4043.  ----------------------------------------------------------------------
  4044.  *
  4045.  * VmMach_MapInDevice --
  4046.  *
  4047.  *    Map a device at some physical address into kernel virtual address.
  4048.  *    This is for use by the controller initialization routines.
  4049.  *    This routine looks for a free page in the special range of
  4050.  *    kernel virtual that is reserved for this kind of thing and
  4051.  *    sets up the page table so that it references the device.
  4052.  *
  4053.  * Results:
  4054.  *    The kernel virtual address needed to reference the device is returned.
  4055.  *
  4056.  * Side effects:
  4057.  *    The hardware page table is modified.  This may steal another
  4058.  *    page from kernel virtual space, unless a page can be cleverly re-used.
  4059.  *
  4060.  *----------------------------------------------------------------------
  4061.  */
  4062. Address
  4063. VmMach_MapInDevice(devPhysAddr, type)
  4064.     Address    devPhysAddr;    /* Physical address of the device to map in */
  4065.     int        type;        /* Value for the page table entry type field.
  4066.                  * This depends on the address space that
  4067.                  * the devices live in, ie. VME D16 or D32 */
  4068. {
  4069.     Address         virtAddr;
  4070.     Address        freeVirtAddr = (Address)0;
  4071.     Address        freePMEGAddr = (Address)0;
  4072.     int            page;
  4073.     int            pageFrame;
  4074.     VmMachPTE        pte;
  4075.  
  4076.     /*
  4077.      * Get the page frame for the physical device so we can
  4078.      * compare it against existing pte's.
  4079.      */
  4080.     pageFrame = (unsigned)devPhysAddr >> VMMACH_PAGE_SHIFT_INT;
  4081.  
  4082.     /*
  4083.      * Spin through the segments and their pages looking for a free
  4084.      * page or a virtual page that is already mapped to the physical page.
  4085.      */
  4086.     for (virtAddr = (Address)VMMACH_DEV_START_ADDR;
  4087.          virtAddr < (Address)VMMACH_DEV_END_ADDR; ) {
  4088.     if (VmMachGetSegMap(virtAddr) == VMMACH_INV_PMEG) {
  4089.         /* 
  4090.          * If we can't find any free mappings we can use this PMEG.
  4091.          */
  4092.         if (freePMEGAddr == 0) {
  4093.         freePMEGAddr = virtAddr;
  4094.         }
  4095.         virtAddr += VMMACH_SEG_SIZE;
  4096.         continue;
  4097.     }
  4098.     /*
  4099.      * Careful, use the correct page size when incrementing virtAddr.
  4100.      * Use the real hardware size (ignore software klustering) because
  4101.      * we are at a low level munging page table entries ourselves here.
  4102.      */
  4103.     for (page = 0;
  4104.          page < VMMACH_NUM_PAGES_PER_SEG_INT;
  4105.          page++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  4106.         pte = VmMachGetPageMap(virtAddr);
  4107.         if (!(pte & VMMACH_RESIDENT_BIT)) {
  4108.             if (freeVirtAddr == 0) {
  4109.             /*
  4110.              * Note the unused page in this special area of the
  4111.              * kernel virtual address space.
  4112.              */
  4113.             freeVirtAddr = virtAddr;
  4114.         }
  4115.         } else if ((pte & VMMACH_PAGE_FRAME_FIELD) == pageFrame &&
  4116.                VmMachGetPageType(pte) == type) {
  4117.         /*
  4118.          * A page is already mapped for this physical address.
  4119.          */
  4120.         return(virtAddr + ((int)devPhysAddr & VMMACH_OFFSET_MASK));
  4121.         }
  4122.     }
  4123.     }
  4124.  
  4125.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | pageFrame;
  4126. #if defined(sun3) || defined(sun4)    /* Not just for porting purposes */
  4127.     pte |= VMMACH_DONT_CACHE_BIT;
  4128. #endif
  4129.     VmMachSetPageType(pte, type);
  4130.     if (freeVirtAddr != 0) {
  4131.     VmMachSetPageMap(freeVirtAddr, pte);
  4132.     /*
  4133.      * Return the kernel virtual address used to access it.
  4134.      */
  4135.     return(freeVirtAddr + ((int)devPhysAddr & VMMACH_OFFSET_MASK));
  4136.     } else if (freePMEGAddr != 0) {
  4137.     int oldContext;
  4138.     int pmeg;
  4139.     int i;
  4140.  
  4141.     /*
  4142.      * Map in a new PMEG so we can use it for mapping.
  4143.      */
  4144.     pmeg = PMEGGet(vm_SysSegPtr, 
  4145.                (int) ((unsigned)freePMEGAddr >> VMMACH_SEG_SHIFT),
  4146.                PMEG_DONT_ALLOC);
  4147.     oldContext = VmMachGetContextReg();
  4148.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  4149.         VmMachSetContextReg(i);
  4150.         VmMachSetSegMap(freePMEGAddr, pmeg);
  4151.     }
  4152.     VmMachSetContextReg(oldContext);
  4153.     VmMachSetPageMap(freePMEGAddr, pte);
  4154.     return(freePMEGAddr + ((int)devPhysAddr & VMMACH_OFFSET_MASK));
  4155.     } else {
  4156.     return((Address)NIL);
  4157.     }
  4158. }
  4159.  
  4160. /*----------------------------------------------------------------------
  4161.  *
  4162.  * DevBufferInit --
  4163.  *
  4164.  *    Initialize a range of virtual memory to allocate from out of the
  4165.  *    device memory space.
  4166.  *
  4167.  * Results:
  4168.  *    None.
  4169.  *
  4170.  * Side effects:
  4171.  *    The buffer struct is initialized and the hardware page map is zeroed
  4172.  *    out in the range of addresses.
  4173.  *
  4174.  *----------------------------------------------------------------------
  4175.  */
  4176. INTERNAL static void
  4177. DevBufferInit()
  4178. {
  4179.     Address        virtAddr;
  4180.     unsigned char    pmeg;
  4181.     int            oldContext;
  4182.     int            i;
  4183.     Address    baseAddr;
  4184.     Address    endAddr;
  4185.  
  4186.     /*
  4187.      * Round base up to next page boundary and end down to page boundary.
  4188.      */
  4189.     baseAddr = (Address)VMMACH_DMA_START_ADDR;
  4190.     endAddr = (Address)(VMMACH_DMA_START_ADDR + VMMACH_DMA_SIZE);
  4191.  
  4192.     /* 
  4193.      * Set up the hardware pages tables in the range of addresses given.
  4194.      */
  4195.     for (virtAddr = baseAddr; virtAddr < endAddr; ) {
  4196.     if (VmMachGetSegMap(virtAddr) != VMMACH_INV_PMEG) {
  4197.         printf("DevBufferInit: DMA space already valid at 0x%x\n",
  4198.            (unsigned int) virtAddr);
  4199.     }
  4200.     /* 
  4201.      * Need to allocate a PMEG.
  4202.      */
  4203.     pmeg = PMEGGet(vm_SysSegPtr, 
  4204.                (int) ((unsigned)virtAddr >> VMMACH_SEG_SHIFT),
  4205.                PMEG_DONT_ALLOC);
  4206.     oldContext = VmMachGetContextReg();
  4207.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  4208.         VmMachSetContextReg(i);
  4209.         VmMachSetSegMap(virtAddr, (int)pmeg);
  4210.     }
  4211.     VmMachSetContextReg(oldContext);
  4212.     virtAddr += VMMACH_SEG_SIZE;
  4213.     }
  4214. }
  4215.  
  4216.  
  4217. static    Boolean    dmaPageBitMap[VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT];
  4218.  
  4219. static Boolean dmaInitialized = FALSE;
  4220.  
  4221. /*
  4222.  ----------------------------------------------------------------------
  4223.  *
  4224.  * VmMach_DMAAlloc --
  4225.  *
  4226.  *    Allocate a set of virtual pages to a routine for mapping purposes.
  4227.  *    
  4228.  * Results:
  4229.  *    Pointer into kernel virtual address space of where to access the
  4230.  *    memory, or NIL if the request couldn't be satisfied.
  4231.  *
  4232.  * Side effects:
  4233.  *    The hardware page table is modified.
  4234.  *
  4235.  *----------------------------------------------------------------------
  4236.  */
  4237. ENTRY Address
  4238. VmMach_DMAAlloc(numBytes, srcAddr)
  4239.     int        numBytes;        /* Number of bytes to map in. */
  4240.     Address    srcAddr;    /* Kernel virtual address to start mapping in.*/
  4241. {
  4242.     Address    beginAddr;
  4243.     Address    endAddr;
  4244.     int        numPages;
  4245.     int        i, j;
  4246.     VmMachPTE    pte;
  4247.     Boolean    foundIt = FALSE;
  4248.     Address    newAddr;
  4249.  
  4250.     MASTER_LOCK(vmMachMutexPtr);
  4251.     if (!dmaInitialized) {
  4252.     /* Where to allocate the memory from. */
  4253.     dmaInitialized = TRUE;
  4254.     DevBufferInit();
  4255.     }
  4256.  
  4257.     /* calculate number of pages needed */
  4258.                         /* beginning of first page */
  4259.     beginAddr = (Address) (((unsigned int)(srcAddr)) & ~VMMACH_OFFSET_MASK_INT);
  4260.                         /* beginning of last page */
  4261.     endAddr = (Address) ((((unsigned int) srcAddr) + numBytes - 1) &
  4262.         ~VMMACH_OFFSET_MASK_INT);
  4263.     numPages = (((unsigned int) endAddr) >> VMMACH_PAGE_SHIFT_INT) -
  4264.         (((unsigned int) beginAddr) >> VMMACH_PAGE_SHIFT_INT) + 1;
  4265.  
  4266.     /* see if request can be satisfied */
  4267.     for (i = 0; i < (VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT); i++) {
  4268.     if (dmaPageBitMap[i] == 1) {
  4269.         continue;
  4270.     }
  4271.     /*
  4272.      * Must be aligned in the cache to avoid write-backs of stale data
  4273.      * from other references to stuff on this page.
  4274.      */
  4275.     newAddr = (Address)(VMMACH_DMA_START_ADDR + (i * VMMACH_PAGE_SIZE_INT));
  4276.     if (((unsigned int) newAddr & (VMMACH_CACHE_SIZE - 1)) !=
  4277.         ((unsigned int) beginAddr & (VMMACH_CACHE_SIZE - 1))) {
  4278.         continue;
  4279.     }
  4280.     for (j = 1; j < numPages &&
  4281.         ((i + j) < (VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT)); j++) {
  4282.         if (dmaPageBitMap[i + j] == 1) {
  4283.         break;
  4284.         }
  4285.     }
  4286.     if (j == numPages &&
  4287.         ((i + j) < (VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT))) {
  4288.         foundIt = TRUE;
  4289.         break;
  4290.     }
  4291.     }
  4292.     if (!foundIt) {
  4293.     MASTER_UNLOCK(vmMachMutexPtr);
  4294.     panic(
  4295.         "VmMach_DMAAlloc: unable to satisfy request for %d bytes at 0x%x\n",
  4296.         numBytes, srcAddr);
  4297. #ifdef NOTDEF
  4298.     return (Address) NIL;
  4299. #endif NOTDEF
  4300.     }
  4301.     for (j = 0; j < numPages; j++) {
  4302.     dmaPageBitMap[i + j] = 1;    /* allocate page */
  4303.     pte = VmMachGetPageMap(srcAddr);
  4304.     pte |= VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT;
  4305.     SET_ALL_PAGE_MAP(((i + j) * VMMACH_PAGE_SIZE_INT) +
  4306.         VMMACH_DMA_START_ADDR, pte);
  4307.     srcAddr += VMMACH_PAGE_SIZE;
  4308.     }
  4309.     beginAddr = (Address) (VMMACH_DMA_START_ADDR + (i * VMMACH_PAGE_SIZE_INT) +
  4310.         (((unsigned int) srcAddr) & VMMACH_OFFSET_MASK));
  4311.  
  4312.     MASTER_UNLOCK(vmMachMutexPtr);
  4313.     return beginAddr;
  4314. }
  4315.  
  4316. /*
  4317.  ----------------------------------------------------------------------
  4318.  *
  4319.  * VmMach_DMAAllocContiguous --
  4320.  *
  4321.  *    WARNING:  this routine doesn't work yet!!
  4322.  *    Allocate a set of virtual pages to a routine for mapping purposes.
  4323.  *    
  4324.  * Results:
  4325.  *    Pointer into kernel virtual address space of where to access the
  4326.  *    memory, or NIL if the request couldn't be satisfied.
  4327.  *
  4328.  * Side effects:
  4329.  *    The hardware page table is modified.
  4330.  *
  4331.  *----------------------------------------------------------------------
  4332.  */
  4333. ReturnStatus
  4334. VmMach_DMAAllocContiguous(inScatGathPtr, scatGathLength, outScatGathPtr)
  4335.     register Net_ScatterGather    *inScatGathPtr;
  4336.     register int        scatGathLength;
  4337.     register Net_ScatterGather    *outScatGathPtr;
  4338. {
  4339.     Address    beginAddr = 0;
  4340.     Address    endAddr;
  4341.     int        numPages;
  4342.     int        i, j;
  4343.     VmMachPTE    pte;
  4344.     Boolean    foundIt = FALSE;
  4345.     int        virtPage;
  4346.     Net_ScatterGather        *inPtr;
  4347.     Net_ScatterGather        *outPtr;
  4348.     int                pageOffset;
  4349.     Address            srcAddr;
  4350.     Address            newAddr;
  4351.  
  4352.     if (!dmaInitialized) {
  4353.     dmaInitialized = TRUE;
  4354.     DevBufferInit();
  4355.     }
  4356.     /* calculate number of pages needed */
  4357.     inPtr = inScatGathPtr;
  4358.     outPtr = outScatGathPtr;
  4359.     numPages = 0;
  4360.     for (i = 0; i < scatGathLength; i++) {
  4361.     if (inPtr->length > 0) {
  4362.         /* beginning of first page */
  4363.         beginAddr = (Address) (((unsigned int)(inPtr->bufAddr)) & 
  4364.             ~VMMACH_OFFSET_MASK_INT);
  4365.         /* beginning of last page */
  4366.         endAddr = (Address) ((((unsigned int) inPtr->bufAddr) + 
  4367.         inPtr->length - 1) & ~VMMACH_OFFSET_MASK_INT);
  4368.         /* 
  4369.          * Temporarily store the number of pages in the out scatter/gather
  4370.          * array.
  4371.          */
  4372.         outPtr->length =
  4373.             (((unsigned int) endAddr) >> VMMACH_PAGE_SHIFT_INT) -
  4374.             (((unsigned int) beginAddr) >> VMMACH_PAGE_SHIFT_INT) + 1;
  4375.     } else {
  4376.         outPtr->length = 0;
  4377.     }
  4378.     if ((i == 0) && (outPtr->length != 1)) {
  4379.         panic("Help! Help! I'm being repressed!\n");
  4380.     }
  4381.     numPages += outPtr->length;
  4382.     inPtr++;
  4383.     outPtr++;
  4384.     }
  4385.  
  4386.     /* see if request can be satisfied */
  4387.     for (i = 0; i < (VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT); i++) {
  4388.     if (dmaPageBitMap[i] == 1) {
  4389.         continue;
  4390.     }
  4391.     /*
  4392.      * Must be aligned in the cache to avoid write-backs of stale data
  4393.      * from other references to stuff on this page.
  4394.      */
  4395.     newAddr = (Address)(VMMACH_DMA_START_ADDR + (i * VMMACH_PAGE_SIZE_INT));
  4396.     if (((unsigned int) newAddr & (VMMACH_CACHE_SIZE - 1)) !=
  4397.         ((unsigned int) beginAddr & (VMMACH_CACHE_SIZE - 1))) {
  4398.         continue;
  4399.     }
  4400.     for (j = 1; j < numPages &&
  4401.         ((i + j) < (VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT)); j++) {
  4402.         if (dmaPageBitMap[i + j] == 1) {
  4403.         break;
  4404.         }
  4405.     }
  4406.     if (j == numPages &&
  4407.         ((i + j) < (VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT))) {
  4408.         foundIt = TRUE;
  4409.         break;
  4410.     }
  4411.     }
  4412.     if (!foundIt) {
  4413.     return FAILURE;
  4414.     }
  4415.     pageOffset = i;
  4416.     inPtr = inScatGathPtr;
  4417.     outPtr = outScatGathPtr;
  4418.     for (i = 0; i < scatGathLength; i++) {
  4419.     srcAddr = inPtr->bufAddr;
  4420.     numPages = outPtr->length;
  4421.     for (j = 0; j < numPages; j++) {
  4422.         dmaPageBitMap[pageOffset + j] = 1;    /* allocate page */
  4423.         virtPage = ((unsigned int) srcAddr) >> VMMACH_PAGE_SHIFT;
  4424.         pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT |
  4425.           VirtToPhysPage(Vm_GetKernPageFrame(virtPage));
  4426.         SET_ALL_PAGE_MAP(((pageOffset + j) * VMMACH_PAGE_SIZE_INT) +
  4427.             VMMACH_DMA_START_ADDR, pte);
  4428.         srcAddr += VMMACH_PAGE_SIZE;
  4429.     }
  4430.     outPtr->bufAddr = (Address) (VMMACH_DMA_START_ADDR + 
  4431.         (pageOffset * VMMACH_PAGE_SIZE_INT) + 
  4432.         (((unsigned int) srcAddr) & VMMACH_OFFSET_MASK));
  4433.     pageOffset += numPages;
  4434.     outPtr->length = inPtr->length;
  4435.     inPtr++;
  4436.     outPtr++;
  4437.     }
  4438.     return SUCCESS;
  4439. }
  4440.  
  4441.  
  4442. /*
  4443.  ----------------------------------------------------------------------
  4444.  *
  4445.  * VmMach_DMAFree --
  4446.  *
  4447.  *    Free a previously allocated set of virtual pages for a routine that
  4448.  *    used them for mapping purposes.
  4449.  *    
  4450.  * Results:
  4451.  *    None.
  4452.  *
  4453.  * Side effects:
  4454.  *    The hardware page table is modified.
  4455.  *
  4456.  *----------------------------------------------------------------------
  4457.  */
  4458. ENTRY void
  4459. VmMach_DMAFree(numBytes, mapAddr)
  4460.     int        numBytes;        /* Number of bytes to map in. */
  4461.     Address    mapAddr;    /* Kernel virtual address to unmap.*/
  4462. {
  4463.     Address    beginAddr;
  4464.     Address    endAddr;
  4465.     int        numPages;
  4466.     int        i, j;
  4467.  
  4468.     MASTER_LOCK(vmMachMutexPtr);
  4469.     /* calculate number of pages to free */
  4470.                         /* beginning of first page */
  4471.     beginAddr = (Address) (((unsigned int) mapAddr) & ~VMMACH_OFFSET_MASK_INT);
  4472.                         /* beginning of last page */
  4473.     endAddr = (Address) ((((unsigned int) mapAddr) + numBytes - 1) &
  4474.         ~VMMACH_OFFSET_MASK_INT);
  4475.     numPages = (((unsigned int) endAddr) >> VMMACH_PAGE_SHIFT_INT) -
  4476.         (((unsigned int) beginAddr) >> VMMACH_PAGE_SHIFT_INT) + 1;
  4477.  
  4478.     i = (((unsigned int) mapAddr) >> VMMACH_PAGE_SHIFT_INT) -
  4479.     (((unsigned int) VMMACH_DMA_START_ADDR) >> VMMACH_PAGE_SHIFT_INT);
  4480.     for (j = 0; j < numPages; j++) {
  4481.     dmaPageBitMap[i + j] = 0;    /* free page */
  4482.     VmMachFlushPage(mapAddr);
  4483.     SET_ALL_PAGE_MAP(mapAddr, (VmMachPTE) 0);
  4484.     (unsigned int) mapAddr += VMMACH_PAGE_SIZE_INT;
  4485.     }
  4486.     MASTER_UNLOCK(vmMachMutexPtr);
  4487.     return;
  4488. }
  4489.  
  4490. #if 0 /* dead code shirriff 9/90 */
  4491.  
  4492. /*
  4493.  * ----------------------------------------------------------------------------
  4494.  *
  4495.  * VmMach_GetDevicePage --
  4496.  *
  4497.  *      Allocate and validate a page at the given virtual address.  It is
  4498.  *    assumed that this page does not fall into the range of virtual 
  4499.  *    addresses used to allocate kernel code and data and that there is
  4500.  *    already a PMEG allocate for it.
  4501.  *
  4502.  * Results:
  4503.  *      None.
  4504.  *
  4505.  * Side effects:
  4506.  *      The hardware segment table for the kernel is modified to validate the
  4507.  *    the page.
  4508.  *
  4509.  * ----------------------------------------------------------------------------
  4510.  */
  4511. void
  4512. VmMach_GetDevicePage(virtAddr) 
  4513.     Address    virtAddr; /* Virtual address where a page has to be 
  4514.                * validated at. */
  4515. {
  4516.     VmMachPTE    pte;
  4517.     int        page;
  4518.  
  4519.     page = Vm_KernPageAllocate();
  4520.     if (page == -1) {
  4521.     panic("Vm_GetDevicePage: Couldn't get memory\n");
  4522.     }
  4523.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | VirtToPhysPage(page) |
  4524.         VMMACH_DONT_CACHE_BIT;
  4525.     SET_ALL_PAGE_MAP(virtAddr, pte);
  4526. }
  4527. #endif
  4528.  
  4529.  
  4530. /*
  4531.  * ----------------------------------------------------------------------------
  4532.  *
  4533.  * VmMach_MapKernelIntoUser --
  4534.  *
  4535.  *      Map a portion of kernel memory into the user's heap segment.  
  4536.  *    It will only map objects on hardware segment boundaries.  This is 
  4537.  *    intended to be used to map devices such as video memory.
  4538.  *
  4539.  *    NOTE: It is assumed that the user process knows what the hell it is
  4540.  *          doing.
  4541.  *
  4542.  * Results:
  4543.  *      Return the virtual address that it chose to map the memory at.
  4544.  *
  4545.  * Side effects:
  4546.  *      The hardware segment table for the user process's segment is modified
  4547.  *    to map in the addresses.
  4548.  *
  4549.  * ----------------------------------------------------------------------------
  4550.  */
  4551. ReturnStatus
  4552. VmMach_MapKernelIntoUser(kernelVirtAddr, numBytes, userVirtAddr,
  4553.              realVirtAddrPtr) 
  4554.     unsigned int    kernelVirtAddr;        /* Kernel virtual address
  4555.                           * to map in. */
  4556.     int    numBytes;                /* Number of bytes to map. */
  4557.     unsigned int    userVirtAddr;         /* User virtual address to
  4558.                           * attempt to start mapping
  4559.                          * in at. */
  4560.     unsigned int    *realVirtAddrPtr;    /* Where we were able to start
  4561.                           * mapping at. */
  4562. {
  4563.     Address             newUserVirtAddr;
  4564.     ReturnStatus        status;
  4565.  
  4566.     status = VmMach_IntMapKernelIntoUser(kernelVirtAddr, numBytes,
  4567.             userVirtAddr, &newUserVirtAddr);
  4568.  
  4569.     if (status != SUCCESS) {
  4570.         return status;
  4571.     }
  4572.  
  4573.     return Vm_CopyOut(4, (Address) &newUserVirtAddr, (Address) realVirtAddrPtr);
  4574. }
  4575.  
  4576.  
  4577. /*
  4578.  * ----------------------------------------------------------------------------
  4579.  *
  4580.  * Vm_IntMapKernelIntoUser --
  4581.  *
  4582.  *      Map a portion of kernel memory into the user's heap segment.
  4583.  *      It will only map objects on hardware segment boundaries.  This is
  4584.  *      intended to be used to map devices such as video memory.
  4585.  *
  4586.  *      This routine can be called from within the kernel since it doesn't
  4587.  *      do a Vm_CopyOut of the new user virtual address.
  4588.  *
  4589.  *      NOTE: It is assumed that the user process knows what the hell it is
  4590.  *            doing.
  4591.  *
  4592.  * Results:
  4593.  *      SUCCESS or FAILURE status.
  4594.  *      Return the virtual address that it chose to map the memory at in
  4595.  *      an out parameter.
  4596.  *
  4597.  * Side effects:
  4598.  *      The hardware segment table for the user process's segment is modified
  4599.  *      to map in the addresses.
  4600.  *
  4601.  * ----------------------------------------------------------------------------
  4602.  */
  4603. ReturnStatus
  4604. VmMach_IntMapKernelIntoUser(kernelVirtAddr, numBytes, userVirtAddr, newAddrPtr)
  4605.     unsigned int        kernelVirtAddr;         /* Kernel virtual address
  4606.                                                  * to map in. */
  4607.     int numBytes;                               /* Number of bytes to map. */
  4608.     unsigned int        userVirtAddr;           /* User virtual address to
  4609.                                                  * attempt to start mapping
  4610.                                                  * in at. */
  4611.     Address             *newAddrPtr;            /* New user address. */
  4612. {
  4613.     int                         numSegs;
  4614.     int                         firstPage;
  4615.     int                         numPages;
  4616.     Proc_ControlBlock           *procPtr;
  4617.     register    Vm_Segment      *segPtr;
  4618.     int                         hardSegNum;
  4619.     int                         i;
  4620.     unsigned int                pte;
  4621.  
  4622. #ifdef NOTDEF
  4623.     /* for debugging */
  4624.     printf("KernelVA 0x%x, numBytes 0x%x, userVA 0x%x.\n",
  4625.             kernelVirtAddr, numBytes, userVirtAddr);
  4626. #endif /* NOTDEF */
  4627.     procPtr = Proc_GetCurrentProc();
  4628.     segPtr = procPtr->vmPtr->segPtrArray[VM_HEAP];
  4629.  
  4630.     numSegs = numBytes >> VMMACH_SEG_SHIFT;
  4631.     numPages = numSegs * VMMACH_SEG_SIZE / VMMACH_PAGE_SIZE;
  4632.  
  4633.     /*
  4634.      * Make user virtual address hardware segment aligned (round up) and
  4635.      * make sure that there is enough space to map things.
  4636.      */
  4637.     hardSegNum =
  4638.             (unsigned int) (userVirtAddr + VMMACH_SEG_SIZE - 1) >> VMMACH_SEG_SHIFT;
  4639.     userVirtAddr = hardSegNum << VMMACH_SEG_SHIFT;
  4640.     if (hardSegNum + numSegs > VMMACH_NUM_SEGS_PER_CONTEXT) {
  4641.         return(SYS_INVALID_ARG);
  4642.     }
  4643.  
  4644.     /*
  4645.      * Make sure will fit into the kernel's VAS.  Assume that is hardware
  4646.      * segment aligned.
  4647.      */
  4648.     hardSegNum = (unsigned int) (kernelVirtAddr) >> VMMACH_SEG_SHIFT;
  4649.     if (hardSegNum + numSegs > VMMACH_NUM_SEGS_PER_CONTEXT) {
  4650.         return(SYS_INVALID_ARG);
  4651.     }
  4652.  
  4653.     /*
  4654.      * Invalidate all virtual memory for the heap segment of this process
  4655.      * in the given range of virtual addresses that we are to map.  This
  4656.      * assures us that there aren't any hardware pages allocated for this
  4657.      * segment in this range of addresses.
  4658.      */
  4659.     firstPage = (unsigned int) (userVirtAddr) >> VMMACH_PAGE_SHIFT;
  4660.     (void)Vm_DeleteFromSeg(segPtr, firstPage, firstPage + numPages - 1);
  4661.  
  4662.     /*
  4663.      * Now go into the kernel's hardware segment table and copy the
  4664.      * segment table entries into the heap segments hardware segment table.
  4665.      */
  4666.  
  4667.     bcopy((Address)GetHardSegPtr(vm_SysSegPtr->machPtr, hardSegNum),
  4668.         (Address)GetHardSegPtr(segPtr->machPtr,
  4669.                 (unsigned int)userVirtAddr >> VMMACH_SEG_SHIFT),
  4670.                 numSegs * sizeof (VMMACH_SEG_NUM));
  4671.     for (i = 0; i < numSegs * VMMACH_NUM_PAGES_PER_SEG_INT; i++) {
  4672.         pte = VmMachGetPageMap((Address)(kernelVirtAddr +
  4673.                 (i * VMMACH_PAGE_SIZE_INT)));
  4674.         pte &= ~VMMACH_KR_PROT;
  4675.         pte |= VMMACH_URW_PROT;
  4676.         VmMachSetPageMap((Address)(kernelVirtAddr + (i*VMMACH_PAGE_SIZE_INT)),
  4677.                 pte);
  4678.     }
  4679.  
  4680.     /*
  4681.      * Make sure this process never migrates.
  4682.      */
  4683.     Proc_NeverMigrate(procPtr);
  4684.  
  4685.     /*
  4686.      * Reinitialize this process's context using the new segment table.
  4687.      */
  4688.     VmMach_ReinitContext(procPtr);
  4689.  
  4690.     *newAddrPtr = (Address) userVirtAddr;
  4691.  
  4692. #ifdef NOTDEF
  4693.     /* for debugging */
  4694.     printf("From Map kernel into user: new user addr is 0x%x.\n",
  4695.             userVirtAddr);
  4696. #endif /* NOTDEF */
  4697.     return SUCCESS;
  4698. }
  4699.  
  4700.  
  4701. /*
  4702.  * ----------------------------------------------------------------------------
  4703.  *
  4704.  * VmMach_Trace --
  4705.  *
  4706.  *      Scan through all of the PMEGs generating trace records for those pages
  4707.  *    that have been referenced or modified since the last time that we
  4708.  *    checked.
  4709.  *  
  4710.  * Results:
  4711.  *      None.
  4712.  *
  4713.  * Side effects:
  4714.  *    None.
  4715.  *
  4716.  * ----------------------------------------------------------------------------
  4717.  */
  4718. ENTRY void
  4719. VmMach_Trace()
  4720. {
  4721.     register    PMEG            *pmegPtr;
  4722.     register    Vm_Segment        *segPtr;
  4723.     register    int            pmegNum;
  4724.     register    int            curTraceTime;
  4725.  
  4726.     MASTER_LOCK(vmMachMutexPtr);
  4727.  
  4728.     /*
  4729.      * Save the current trace time and then increment it to ensure that
  4730.      * any segments that get used while we are scanning memory won't get 
  4731.      * missed.
  4732.      */
  4733.     curTraceTime = vmTraceTime;
  4734.     vmTraceTime++;
  4735.  
  4736.     /*
  4737.      * Spin through all of the pmegs.
  4738.      */
  4739.     for (pmegNum = 0, pmegPtr = pmegArray;
  4740.      pmegNum < VMMACH_NUM_PMEGS;
  4741.      pmegPtr++, pmegNum++) {
  4742.     segPtr = pmegPtr->segInfo.segPtr;
  4743.     if ((pmegPtr->flags & PMEG_NEVER_FREE) ||
  4744.         segPtr == (Vm_Segment *)NIL ||
  4745.         segPtr->traceTime < curTraceTime) {
  4746.         continue;
  4747.     }
  4748.     vmTraceStats.machStats.pmegsChecked++;
  4749.     printedSegTrace = FALSE;
  4750.     tracePMEGPtr = pmegPtr;
  4751.     VmMachTracePMEG(pmegNum);
  4752.     }
  4753.  
  4754.     MASTER_UNLOCK(vmMachMutexPtr);
  4755.  
  4756.     VmCheckTraceOverflow();
  4757. }
  4758.  
  4759.  
  4760. /*
  4761.  * ----------------------------------------------------------------------------
  4762.  *
  4763.  * VmMachTracePage --
  4764.  *
  4765.  *      Generate a trace record for the given page.
  4766.  *  
  4767.  * Results:
  4768.  *      None.
  4769.  *
  4770.  * Side effects:
  4771.  *    None.
  4772.  *
  4773.  * ----------------------------------------------------------------------------
  4774.  */
  4775. static void
  4776. VmMachTracePage(pte, pageNum)
  4777.     register    VmMachPTE    pte;    /* Page table entry to be traced. */
  4778.     unsigned    int        pageNum;/* Inverse of page within PMEG. */
  4779. {
  4780.     Vm_TraceSeg            segTrace;
  4781.     Vm_TracePage        pageTrace;
  4782.     register    PMEG        *pmegPtr;
  4783.     register    Vm_Segment    *segPtr = (Vm_Segment *)NIL;
  4784.  
  4785.     refModMap[PhysToVirtPage(pte & VMMACH_PAGE_FRAME_FIELD)] |=
  4786.             pte & (VMMACH_REFERENCED_BIT | VMMACH_MODIFIED_BIT);
  4787.     if (!printedSegTrace) {
  4788.     /*
  4789.      * Trace of the segment.
  4790.      */
  4791.     printedSegTrace = TRUE;
  4792.     pmegPtr = tracePMEGPtr;
  4793.     segPtr = pmegPtr->segInfo.segPtr;
  4794.     segTrace.hardSegNum = pmegPtr->segInfo.hardSegNum;
  4795.     segTrace.softSegNum = segPtr->segNum;
  4796.     segTrace.segType = segPtr->type;
  4797.     segTrace.refCount = segPtr->refCount;
  4798.     VmStoreTraceRec(VM_TRACE_SEG_REC, sizeof(Vm_TraceSeg), 
  4799.             (Address)&segTrace, FALSE);
  4800.     }
  4801.  
  4802.     /*
  4803.      * Trace the page.
  4804.      */
  4805.     pageTrace = VMMACH_NUM_PAGES_PER_SEG_INT - pageNum;
  4806.     if (pte & VMMACH_REFERENCED_BIT) {
  4807.     pageTrace |= VM_TRACE_REFERENCED;
  4808.     } 
  4809.     if (pte & VMMACH_MODIFIED_BIT) {
  4810.     pageTrace |= VM_TRACE_MODIFIED;
  4811.     }
  4812.     VmStoreTraceRec(0, sizeof(Vm_TracePage), (Address)&pageTrace, FALSE);
  4813. }
  4814.  
  4815.  
  4816. /*
  4817.  *----------------------------------------------------------------------
  4818.  *
  4819.  * VmMach_FlushPage --
  4820.  *
  4821.  *    Flush the page at the given virtual address from all caches.  We
  4822.  *    don't have to do anything on the Sun-2 and Sun-3 workstations
  4823.  *    that we have.
  4824.  *
  4825.  * Results:
  4826.  *    None.
  4827.  *
  4828.  * Side effects:
  4829.  *    The given page is flushed from the caches.
  4830.  *
  4831.  *----------------------------------------------------------------------
  4832.  */
  4833. /*ARGSUSED*/
  4834. void
  4835. VmMach_FlushPage(virtAddrPtr, invalidate)
  4836.     Vm_VirtAddr    *virtAddrPtr;
  4837.     Boolean    invalidate;    /* Should invalidate the pte after flushing. */
  4838. {
  4839.     Address    virtAddr;
  4840.  
  4841.     /* on sun4, ignore invalidate parameter? */
  4842.     virtAddr = (Address) (virtAddrPtr->page << VMMACH_PAGE_SHIFT);
  4843.     VmMachFlushPage(virtAddr);
  4844.     if (invalidate) {
  4845.     VmMachSetPageMap(virtAddr, (VmMachPTE)0);
  4846.     }
  4847.     return;
  4848. }
  4849.  
  4850.  
  4851. /*
  4852.  *----------------------------------------------------------------------
  4853.  *
  4854.  * VmMach_SetProtForDbg --
  4855.  *
  4856.  *    Set the protection of the kernel pages for the debugger.
  4857.  *
  4858.  * Results:
  4859.  *    None.
  4860.  *
  4861.  * Side effects:
  4862.  *    The protection is set for the given range of kernel addresses.
  4863.  *
  4864.  *----------------------------------------------------------------------
  4865.  */
  4866. void
  4867. VmMach_SetProtForDbg(readWrite, numBytes, addr)
  4868.     Boolean    readWrite;    /* TRUE if should make pages writable, FALSE
  4869.                  * if should make read-only. */
  4870.     int        numBytes;    /* Number of bytes to change protection for. */
  4871.     Address    addr;        /* Address to start changing protection at. */
  4872. {
  4873.     register    Address        virtAddr;
  4874.     register    VmMachPTE     pte;
  4875.     register    int        firstPage;
  4876.     register    int        lastPage;
  4877.     int        oldContext;
  4878.     int        i;
  4879.  
  4880.     /*
  4881.      * This should only be called with kernel text pages so we modify the
  4882.      * PTE for the address in all the contexts. Note that we must flush
  4883.      * the page from the change before changing the protections to avoid
  4884.      * write back errors.
  4885.      */
  4886.     oldContext = VmMachGetContextReg();
  4887.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  4888.     VmMachSetContextReg(i);
  4889.     firstPage = (unsigned)addr >> VMMACH_PAGE_SHIFT;
  4890.     lastPage = ((unsigned)addr + numBytes - 1) >> VMMACH_PAGE_SHIFT;
  4891.     for (; firstPage <= lastPage; firstPage++) {
  4892.         virtAddr = (Address) (firstPage << VMMACH_PAGE_SHIFT);
  4893.         pte = VmMachGetPageMap(virtAddr);
  4894.         pte &= ~VMMACH_PROTECTION_FIELD;
  4895.         pte |= readWrite ? VMMACH_KRW_PROT : VMMACH_KR_PROT;
  4896.         VmMachFlushPage(virtAddr);
  4897.         SET_ALL_PAGE_MAP(virtAddr, pte);
  4898.     }
  4899.     }
  4900.     VmMachSetContextReg(oldContext);
  4901. }
  4902.  
  4903.  
  4904. /*
  4905.  *----------------------------------------------------------------------
  4906.  *
  4907.  * VmMach_Cmd --
  4908.  *
  4909.  *    Machine dependent vm commands.
  4910.  *
  4911.  * Results:
  4912.  *    None.
  4913.  *
  4914.  * Side effects:
  4915.  *    None.
  4916.  *
  4917.  *----------------------------------------------------------------------
  4918.  */
  4919. /*ARGSUSED*/
  4920. ReturnStatus
  4921. VmMach_Cmd(command, arg)
  4922.     int    command;
  4923.     int arg;
  4924. {
  4925.     return(GEN_INVALID_ARG);
  4926. }
  4927.  
  4928.  
  4929. /*
  4930.  *----------------------------------------------------------------------
  4931.  *
  4932.  * VmMach_HandleSegMigration --
  4933.  *
  4934.  *    Do machine-dependent aspects of segment migration.  On the sun4's,
  4935.  *    this means flush the segment from the virtually addressed cache.
  4936.  *
  4937.  * Results:
  4938.  *    None.
  4939.  *
  4940.  * Side effects:
  4941.  *    None.
  4942.  *
  4943.  *----------------------------------------------------------------------
  4944.  */
  4945. void
  4946. VmMach_HandleSegMigration(segPtr)
  4947.     Vm_Segment        *segPtr;    /* Pointer to segment to be migrated. */
  4948. {
  4949.     Address    virtAddr;
  4950.  
  4951.     virtAddr = (Address) (segPtr->offset << VMMACH_PAGE_SHIFT);
  4952.     VmMachFlushSegment(virtAddr);
  4953.  
  4954.     return;
  4955. }
  4956.  
  4957.  
  4958. /*
  4959.  *----------------------------------------------------------------------
  4960.  *
  4961.  * VmMach_FlushCode --
  4962.  *
  4963.  *      Does nothing on this machine.
  4964.  *
  4965.  * Results:
  4966.  *      None.
  4967.  *
  4968.  * Side effects:
  4969.  *      None.
  4970.  *
  4971.  *----------------------------------------------------------------------
  4972.  */
  4973. /*ARGSUSED*/
  4974. void
  4975. VmMach_FlushCode(procPtr, virtAddrPtr, virtPage, numBytes)
  4976.     Proc_ControlBlock   *procPtr;
  4977.     Vm_VirtAddr         *virtAddrPtr;
  4978.     unsigned            virtPage;
  4979.     int                 numBytes;
  4980. {
  4981. }
  4982.  
  4983.  
  4984. /*
  4985.  * Dummy function which will turn out to be the function that the debugger
  4986.  * prints out on a backtrace after a trap.  The debugger gets confused
  4987.  * because trap stacks originate from assembly language stacks.  I decided
  4988.  * to make a dummy procedure because it was to confusing seeing the
  4989.  * previous procedure (VmMach_MapKernelIntoUser) on every backtrace.
  4990.  */
  4991. static void
  4992. VmMachTrap()
  4993. {
  4994. }
  4995.  
  4996. /*
  4997.  * This looks like dead code.
  4998.  */
  4999. #if 0
  5000. /*
  5001.  *----------------------------------------------------------------------
  5002.  *
  5003.  * ByteFill --
  5004.  *
  5005.  *    Fill numBytes at the given address.  This routine is optimized to do 
  5006.  *      4-byte fills.  However, if the address is odd then it is forced to
  5007.  *      do single byte fills.
  5008.  *
  5009.  * Results:
  5010.  *    numBytes bytes of the fill byte are placed at *destPtr at the 
  5011.  *    given address.
  5012.  *
  5013.  * Side effects:
  5014.  *    None.
  5015.  *
  5016.  *----------------------------------------------------------------------
  5017.  */
  5018.  
  5019. static void
  5020. ByteFill(fillByte, numBytes, destPtr)
  5021.     register unsigned char fillByte;    /* The byte to be filled in. */
  5022.     register int numBytes;    /* The number of bytes to be filled in. */
  5023.     Address destPtr;        /* Where to fill. */
  5024. {
  5025.     register unsigned int fillInt = 
  5026.     (fillByte) | (fillByte << 8) | (fillByte << 16) | (fillByte << 24);
  5027.  
  5028.     register int *dPtr = (int *) destPtr;
  5029.     
  5030.     /*
  5031.      * If the address is on an aligned boundary then fill in as much
  5032.      * as we can in big transfers (and also avoid loop overhead by
  5033.      * storing many fill ints per iteration).  Once we have less than
  5034.      * 4 bytes to fill then it must be done by byte copies.
  5035.      */
  5036.     /*
  5037.      * On the sun4, I should try double-words...
  5038.      */
  5039. #define WORDMASK    0x1
  5040.  
  5041.     if (((int) dPtr & WORDMASK) == 0) {
  5042.     while (numBytes >= 32) {
  5043.         *dPtr++ = fillInt;
  5044.         *dPtr++ = fillInt;
  5045.         *dPtr++ = fillInt;
  5046.         *dPtr++ = fillInt;
  5047.         *dPtr++ = fillInt;
  5048.         *dPtr++ = fillInt;
  5049.         *dPtr++ = fillInt;
  5050.         *dPtr++ = fillInt;
  5051.         numBytes -= 32;
  5052.     }
  5053.     while (numBytes >= 4) {
  5054.         *dPtr++ = fillInt;
  5055.         numBytes -= 4;
  5056.     }
  5057.     destPtr = (char *) dPtr;
  5058.     }
  5059.  
  5060.     /*
  5061.      * Fill in the remaining bytes
  5062.      */
  5063.  
  5064.     while (numBytes > 0) {
  5065.     *destPtr++ = fillByte;
  5066.     numBytes--;
  5067.     }
  5068. }
  5069. #endif
  5070.  
  5071. #ifndef sun4c
  5072.  
  5073. /*----------------------------------------------------------------------
  5074.  *
  5075.  * Dev32BitBufferInit --
  5076.  *
  5077.  *    Initialize a range of virtual memory to allocate from out of the
  5078.  *    device memory space.
  5079.  *
  5080.  * Results:
  5081.  *    None.
  5082.  *
  5083.  * Side effects:
  5084.  *    The buffer struct is initialized and the hardware page map is zeroed
  5085.  *    out in the range of addresses.
  5086.  *
  5087.  *----------------------------------------------------------------------
  5088.  */
  5089. INTERNAL static void
  5090. Dev32BitDMABufferInit()
  5091. {
  5092.     Address        virtAddr;
  5093.     unsigned char    pmeg;
  5094.     int            oldContext;
  5095.     Address    baseAddr;
  5096.     Address    endAddr;
  5097.  
  5098.     if ((VMMACH_32BIT_DMA_SIZE & (VMMACH_CACHE_SIZE - 1)) != 0) {
  5099.     panic(
  5100. "Dev32BitDMABufferInit: 32-bit DMA area must be a multiple of cache size.\n");
  5101.     }
  5102.  
  5103.     VmMachSetup32BitDVMA(); 
  5104.     /*
  5105.      * Round base up to next page boundary and end down to page boundary.
  5106.      */
  5107.     baseAddr = (Address)VMMACH_32BIT_DMA_START_ADDR;
  5108.     endAddr = (Address)(VMMACH_32BIT_DMA_START_ADDR + VMMACH_32BIT_DMA_SIZE);
  5109.  
  5110.     /* 
  5111.      * Set up the hardware pages tables in the range of addresses given.
  5112.      */
  5113.     oldContext = VmMachGetContextReg();
  5114.     VmMachSetContextReg(0);
  5115.     for (virtAddr = baseAddr; virtAddr < endAddr; ) {
  5116.     if (VmMachGetSegMap(virtAddr) != VMMACH_INV_PMEG) {
  5117.         printf("Dev32BitDMABufferInit: DMA space already valid at 0x%x\n",
  5118.            (unsigned int) virtAddr);
  5119.     }
  5120.     /* 
  5121.      * Need to allocate a PMEG.
  5122.      */
  5123.     pmeg = PMEGGet(vm_SysSegPtr, 
  5124.                (int) ((unsigned)virtAddr >> VMMACH_SEG_SHIFT),
  5125.                PMEG_DONT_ALLOC);
  5126.     if (pmeg == VMMACH_INV_PMEG) {
  5127.         panic("Dev32BitDMABufferInit: unable to get a pmeg.\n");
  5128.     }
  5129.         VmMachSetSegMap(virtAddr, (int)pmeg);
  5130.     virtAddr += VMMACH_SEG_SIZE;
  5131.     }
  5132.     VmMachSetContextReg(oldContext);
  5133. }
  5134.  
  5135.  
  5136. static    Boolean    userdmaPageBitMap[VMMACH_32BIT_DMA_SIZE / VMMACH_PAGE_SIZE_INT];
  5137.  
  5138.  
  5139. /*
  5140.  ----------------------------------------------------------------------
  5141.  *
  5142.  * VmMach_32BitDMAAlloc --
  5143.  *
  5144.  *    Allocate a set of virtual pages to a routine for mapping purposes.
  5145.  *    
  5146.  * Results:
  5147.  *    Pointer into kernel virtual address space of where to access the
  5148.  *    memory, or NIL if the request couldn't be satisfied.
  5149.  *
  5150.  * Side effects:
  5151.  *    The hardware page table is modified.
  5152.  *
  5153.  *----------------------------------------------------------------------
  5154.  */
  5155. ENTRY Address
  5156. VmMach_32BitDMAAlloc(numBytes, srcAddr)
  5157.     int        numBytes;        /* Number of bytes to map in. */
  5158.     Address    srcAddr;    /* Kernel virtual address to start mapping in.*/
  5159. {
  5160.     Address    beginAddr;
  5161.     Address    endAddr;
  5162.     int        numPages;
  5163.     int        i, j;
  5164.     VmMachPTE    pte;
  5165.     Boolean    foundIt = FALSE;
  5166.     static initialized = FALSE;
  5167.     unsigned    oldContext;
  5168.     int        align;
  5169.  
  5170.     MASTER_LOCK(vmMachMutexPtr);
  5171.     if (!initialized) {
  5172.     initialized = TRUE;
  5173.     Dev32BitDMABufferInit();
  5174.     }
  5175.  
  5176.     /* calculate number of pages needed */
  5177.                         /* beginning of first page */
  5178.     beginAddr = (Address) (((unsigned int)(srcAddr)) & ~VMMACH_OFFSET_MASK_INT);
  5179.                         /* beginning of last page */
  5180.     endAddr = (Address) ((((unsigned int) srcAddr) + numBytes - 1) &
  5181.         ~VMMACH_OFFSET_MASK_INT);
  5182.     numPages = (((unsigned int) endAddr) >> VMMACH_PAGE_SHIFT_INT) -
  5183.         (((unsigned int) beginAddr) >> VMMACH_PAGE_SHIFT_INT) + 1;
  5184.  
  5185.     /* set first addr to first entry that is also cache aligned */
  5186.     align = (unsigned int) beginAddr & (VMMACH_CACHE_SIZE - 1);
  5187.     align -= (unsigned int) VMMACH_32BIT_DMA_START_ADDR &
  5188.         (VMMACH_CACHE_SIZE - 1);
  5189.     if ((int) align < 0) {
  5190.     align += VMMACH_CACHE_SIZE;
  5191.     }
  5192.     /* see if request can be satisfied, incrementing by cache size in loop */
  5193.     for (i = align / VMMACH_PAGE_SIZE_INT;
  5194.         i < (VMMACH_32BIT_DMA_SIZE / VMMACH_PAGE_SIZE_INT);
  5195.         i += (VMMACH_CACHE_SIZE / VMMACH_PAGE_SIZE_INT)) {
  5196.     if (userdmaPageBitMap[i] == 1) {
  5197.         continue;
  5198.     }
  5199.     for (j = 1; (j < numPages) &&
  5200.         ((i + j) < (VMMACH_32BIT_DMA_SIZE / VMMACH_PAGE_SIZE_INT));
  5201.         j++) {
  5202.         if (userdmaPageBitMap[i + j] == 1) {
  5203.         break;
  5204.         }
  5205.     }
  5206.     if ((j == numPages) &&
  5207.         ((i + j) < (VMMACH_32BIT_DMA_SIZE / VMMACH_PAGE_SIZE_INT))) {
  5208.         foundIt = TRUE;
  5209.         break;
  5210.     }
  5211.     }
  5212.  
  5213.     if (!foundIt) {
  5214.     MASTER_UNLOCK(vmMachMutexPtr);
  5215.     panic(
  5216.     "VmMach_32BitDMAAlloc: unable to satisfy request for %d bytes at 0x%x\n",
  5217.         numBytes, srcAddr);
  5218. #ifdef NOTDEF
  5219.     return (Address) NIL;
  5220. #endif NOTDEF
  5221.     }
  5222.     oldContext = VmMachGetContextReg();
  5223.     VmMachSetContextReg(0);
  5224.     for (j = 0; j < numPages; j++) {
  5225.     userdmaPageBitMap[i + j] = 1;    /* allocate page */
  5226.     pte = VmMachGetPageMap(srcAddr);
  5227.     pte = (pte & ~VMMACH_PROTECTION_FIELD) | VMMACH_RESIDENT_BIT | 
  5228.             VMMACH_URW_PROT;
  5229.  
  5230.     SET_ALL_PAGE_MAP(((i + j) * VMMACH_PAGE_SIZE_INT) +
  5231.         VMMACH_32BIT_DMA_START_ADDR, pte);
  5232.     srcAddr += VMMACH_PAGE_SIZE;
  5233.     }
  5234.     VmMachSetContextReg((int)oldContext);
  5235.     beginAddr = (Address) (VMMACH_32BIT_DMA_START_ADDR +
  5236.         (i * VMMACH_PAGE_SIZE_INT) +
  5237.         (((unsigned int) srcAddr) & VMMACH_OFFSET_MASK));
  5238.  
  5239.     /* set high VME addr bit */
  5240.     (unsigned) beginAddr |= VMMACH_VME_ADDR_BIT;
  5241.     MASTER_UNLOCK(vmMachMutexPtr);
  5242.     return (Address) beginAddr;
  5243. }
  5244.  
  5245.  
  5246. /*
  5247.  ----------------------------------------------------------------------
  5248.  *
  5249.  * VmMach_32BitDMAFree --
  5250.  *
  5251.  *    Free a previously allocated set of virtual pages for a routine that
  5252.  *    used them for mapping purposes.
  5253.  *    
  5254.  * Results:
  5255.  *    None.
  5256.  *
  5257.  * Side effects:
  5258.  *    The hardware page table is modified.
  5259.  *
  5260.  *----------------------------------------------------------------------
  5261.  */
  5262. ENTRY void
  5263. VmMach_32BitDMAFree(numBytes, mapAddr)
  5264.     int        numBytes;        /* Number of bytes to map in. */
  5265.     Address    mapAddr;    /* Kernel virtual address to unmap.*/
  5266. {
  5267.     Address    beginAddr;
  5268.     Address    endAddr;
  5269.     int        numPages;
  5270.     int        i, j;
  5271.     int         oldContext;
  5272.  
  5273.     MASTER_LOCK(vmMachMutexPtr);
  5274.     /* calculate number of pages to free */
  5275.     /* Clear the VME high bit from the address */
  5276.     mapAddr = (Address) ((unsigned)mapAddr & ~VMMACH_VME_ADDR_BIT);
  5277.                         /* beginning of first page */
  5278.     beginAddr = (Address) (((unsigned int) mapAddr) & ~VMMACH_OFFSET_MASK_INT);
  5279.                         /* beginning of last page */
  5280.     endAddr = (Address) ((((unsigned int) mapAddr) + numBytes - 1) &
  5281.         ~VMMACH_OFFSET_MASK_INT);
  5282.     numPages = (((unsigned int) endAddr) >> VMMACH_PAGE_SHIFT_INT) -
  5283.         (((unsigned int) beginAddr) >> VMMACH_PAGE_SHIFT_INT) + 1;
  5284.  
  5285.     i = (((unsigned int) mapAddr) >> VMMACH_PAGE_SHIFT_INT) -
  5286.     (((unsigned int) VMMACH_32BIT_DMA_START_ADDR) >> VMMACH_PAGE_SHIFT_INT);
  5287.     oldContext = VmMachGetContextReg();
  5288.     VmMachSetContextReg(0);
  5289.     for (j = 0; j < numPages; j++) {
  5290.     userdmaPageBitMap[i + j] = 0;    /* free page */
  5291.     VmMachFlushPage(mapAddr);
  5292.     SET_ALL_PAGE_MAP(mapAddr, (VmMachPTE) 0);
  5293.     (unsigned int) mapAddr += VMMACH_PAGE_SIZE_INT;
  5294.     }
  5295.     VmMachSetContextReg(oldContext);
  5296.     MASTER_UNLOCK(vmMachMutexPtr);
  5297.     return;
  5298. }
  5299.  
  5300. #endif /* not sun4c */
  5301.  
  5302.  
  5303. #define CHECK(x) (((x)<0||(x)>=VMMACH_SHARED_NUM_BLOCKS)?\
  5304.     panic("Alloc out of bounds"):0)
  5305. #define ALLOC(x,s)    (CHECK(x),sharedData->allocVector[(x)]=s)
  5306. #define FREE(x)        (CHECK(x),sharedData->allocVector[(x)]=0)
  5307. #define SIZE(x)        (CHECK(x),sharedData->allocVector[(x)])
  5308. #define ISFREE(x)    (CHECK(x),sharedData->allocVector[(x)]==0)
  5309.  
  5310.  
  5311.  
  5312. /*
  5313.  * ----------------------------------------------------------------------------
  5314.  *
  5315.  * VmMach_Alloc --
  5316.  *
  5317.  *      Allocates a region of shared memory;
  5318.  *
  5319.  * Results:
  5320.  *      SUCCESS if the region can be allocated.
  5321.  *    The starting address is returned in addr.
  5322.  *
  5323.  * Side effects:
  5324.  *      The allocation vector is updated.
  5325.  *
  5326.  * ----------------------------------------------------------------------------
  5327.  */
  5328. static ReturnStatus
  5329. VmMach_Alloc(sharedData, regionSize, addr)
  5330.     VmMach_SharedData    *sharedData;    /* Pointer to shared memory info.  */
  5331.     int            regionSize;    /* Size of region to allocate. */
  5332.     Address        *addr;        /* Address of region. */
  5333. {
  5334.     int numBlocks = (regionSize+VMMACH_SHARED_BLOCK_SIZE-1) /
  5335.         VMMACH_SHARED_BLOCK_SIZE;
  5336.     int i, blockCount, firstBlock;
  5337.  
  5338.     if (sharedData->allocVector == (int *)NULL || sharedData->allocVector ==
  5339.         (int *)NIL) {
  5340.     dprintf("VmMach_Alloc: allocVector uninitialized!\n");
  5341.     }
  5342.  
  5343.     /*
  5344.      * Loop through the alloc vector until we find numBlocks free blocks
  5345.      * consecutively.
  5346.      */
  5347.     blockCount = 0;
  5348.     for (i=sharedData->allocFirstFree;
  5349.         i<=VMMACH_SHARED_NUM_BLOCKS-1 && blockCount<numBlocks;i++) {
  5350.     if (ISFREE(i)) {
  5351.         blockCount++;
  5352.     } else {
  5353.         blockCount = 0;
  5354.         if (i==sharedData->allocFirstFree) {
  5355.         sharedData->allocFirstFree++;
  5356.         }
  5357.     }
  5358.     }
  5359.     if (blockCount < numBlocks) {
  5360.     dprintf("VmMach_Alloc: got %d blocks of %d of %d total\n",
  5361.         blockCount,numBlocks,VMMACH_SHARED_NUM_BLOCKS);
  5362.     return VM_NO_SEGMENTS;
  5363.     }
  5364.     firstBlock = i-blockCount;
  5365.     if (firstBlock == sharedData->allocFirstFree) {
  5366.     sharedData->allocFirstFree += blockCount;
  5367.     }
  5368.     *addr = (Address)(firstBlock*VMMACH_SHARED_BLOCK_SIZE +
  5369.         VMMACH_SHARED_START_ADDR);
  5370.     for (i = firstBlock; i<firstBlock+numBlocks; i++) {
  5371.     ALLOC(i,numBlocks);
  5372.     }
  5373.     dprintf("VmMach_Alloc: got %d blocks at %d (%x)\n",
  5374.         numBlocks,firstBlock,*addr);
  5375.     return SUCCESS;
  5376. }
  5377.  
  5378.  
  5379. /*
  5380.  * ----------------------------------------------------------------------------
  5381.  *
  5382.  * VmMach_Unalloc --
  5383.  *
  5384.  *      Frees a region of shared address space.
  5385.  *
  5386.  * Results:
  5387.  *      None.
  5388.  *
  5389.  * Side effects:
  5390.  *      The allocation vector is updated.
  5391.  *
  5392.  * ----------------------------------------------------------------------------
  5393.  */
  5394.  
  5395. static void
  5396. VmMach_Unalloc(sharedData, addr)
  5397.     VmMach_SharedData    *sharedData;    /* Pointer to shared memory info. */
  5398.     Address    addr;        /* Address of region. */
  5399. {
  5400.     int firstBlock = ((int)addr-VMMACH_SHARED_START_ADDR) /
  5401.         VMMACH_SHARED_BLOCK_SIZE;
  5402.     int numBlocks;
  5403.     int i;
  5404.  
  5405.     if (firstBlock<0 || firstBlock>=VMMACH_SHARED_NUM_BLOCKS) {
  5406.     if (debugVmStubs) {
  5407.         printf("VmMach_Unalloc: addr %x out of range\n", addr);
  5408.     }
  5409.     return;
  5410.     }
  5411.  
  5412.     numBlocks = SIZE(firstBlock);
  5413.  
  5414.     dprintf("VmMach_Unalloc: freeing %d blocks at %x\n",numBlocks,addr);
  5415.     if (firstBlock < sharedData->allocFirstFree) {
  5416.     sharedData->allocFirstFree = firstBlock;
  5417.     }
  5418.     for (i=0;i<numBlocks;i++) {
  5419.     if (ISFREE(i+firstBlock)) {
  5420.         if (debugVmStubs) {
  5421.         printf("Freeing free shared address %d %d %x\n",i,i+firstBlock,
  5422.             (int)addr);
  5423.         }
  5424.         return;
  5425.     }
  5426.     FREE(i+firstBlock);
  5427.     }
  5428. }
  5429.  
  5430. /*
  5431.  * ----------------------------------------------------------------------------
  5432.  *
  5433.  * VmMach_SharedStartAddr --
  5434.  *
  5435.  *      Determine the starting address for a shared segment.
  5436.  *
  5437.  * Results:
  5438.  *      Returns the proper start address for the segment.
  5439.  *
  5440.  * Side effects:
  5441.  *      Allocates part of the shared address space.
  5442.  *
  5443.  * ----------------------------------------------------------------------------
  5444.  */
  5445. /*ARGSUSED*/
  5446. ReturnStatus
  5447. VmMach_SharedStartAddr(procPtr,size,reqAddr, fixed)
  5448.     Proc_ControlBlock    *procPtr;
  5449.     int             size;           /* Length of shared segment. */
  5450.     Address         *reqAddr;        /* Requested start address. */
  5451.     int            fixed;        /* 1 if fixed address requested. */
  5452. {
  5453.     int numBlocks = (size+VMMACH_SHARED_BLOCK_SIZE-1) /
  5454.         VMMACH_SHARED_BLOCK_SIZE;
  5455.     int firstBlock = (((int)*reqAddr)-VMMACH_SHARED_START_ADDR+
  5456.         VMMACH_SHARED_BLOCK_SIZE-1) /
  5457.         VMMACH_SHARED_BLOCK_SIZE;
  5458.     int i;
  5459.     VmMach_SharedData    *sharedData = &procPtr->vmPtr->machPtr->sharedData;
  5460.  
  5461.     if (fixed==0) {
  5462.     return VmMach_Alloc(sharedData, size, reqAddr);
  5463.     } else {
  5464.     for (i = firstBlock; i<firstBlock+numBlocks; i++) {
  5465.         if (i>0) {
  5466.         ALLOC(i,numBlocks);
  5467.         }
  5468.     }
  5469.     return SUCCESS;
  5470.     }
  5471. }
  5472.  
  5473. /*
  5474.  * ----------------------------------------------------------------------------
  5475.  *
  5476.  * VmMach_SharedProcStart --
  5477.  *
  5478.  *      Perform machine dependent initialization of shared memory
  5479.  *    for this process.
  5480.  *
  5481.  * Results:
  5482.  *      None.
  5483.  *
  5484.  * Side effects:
  5485.  *      The storage allocation structures are initialized.
  5486.  *
  5487.  * ----------------------------------------------------------------------------
  5488.  */
  5489. void
  5490. VmMach_SharedProcStart(procPtr)
  5491.     Proc_ControlBlock    *procPtr;
  5492. {
  5493.     VmMach_SharedData    *sharedData = &procPtr->vmPtr->machPtr->sharedData;
  5494.     dprintf("VmMach_SharedProcStart: initializing proc's allocVector\n");
  5495.     if (sharedData->allocVector != (int *)NIL) {
  5496.     panic("VmMach_SharedProcStart: allocVector not NIL\n");
  5497.     }
  5498.     sharedData->allocVector =
  5499.         (int *)malloc(VMMACH_SHARED_NUM_BLOCKS*sizeof(int));
  5500.     if (debugVmStubs) {
  5501.     printf("Initializing allocVector for %x to %x\n", procPtr->processID,
  5502.         sharedData->allocVector);
  5503.     }
  5504.     sharedData->allocFirstFree = 0;
  5505.     bzero((Address) sharedData->allocVector, VMMACH_SHARED_NUM_BLOCKS*
  5506.         sizeof(int));
  5507.     procPtr->vmPtr->sharedStart = (Address) 0x00000000;
  5508.     procPtr->vmPtr->sharedEnd = (Address) 0xffff0000;
  5509. }
  5510.  
  5511. /*
  5512.  * ----------------------------------------------------------------------------
  5513.  *
  5514.  * VmMach_SharedSegFinish --
  5515.  *
  5516.  *      Perform machine dependent cleanup of shared memory
  5517.  *    for this segment.
  5518.  *
  5519.  * Results:
  5520.  *      None.
  5521.  *
  5522.  * Side effects:
  5523.  *      The storage allocation structures are freed.
  5524.  *
  5525.  * ----------------------------------------------------------------------------
  5526.  */
  5527. void
  5528. VmMach_SharedSegFinish(procPtr,addr)
  5529.     Proc_ControlBlock    *procPtr;
  5530.     Address        addr;
  5531. {
  5532.     VmMach_Unalloc(&procPtr->vmPtr->machPtr->sharedData,addr);
  5533. }
  5534.  
  5535. /*
  5536.  * ----------------------------------------------------------------------------
  5537.  *
  5538.  * VmMach_SharedProcFinish --
  5539.  *
  5540.  *      Perform machine dependent cleanup of shared memory
  5541.  *    for this process.
  5542.  *
  5543.  * Results:
  5544.  *      None.
  5545.  *
  5546.  * Side effects:
  5547.  *      The storage allocation structures are freed.
  5548.  *
  5549.  * ----------------------------------------------------------------------------
  5550.  */
  5551. void
  5552. VmMach_SharedProcFinish(procPtr)
  5553.     Proc_ControlBlock    *procPtr;
  5554. {
  5555.     dprintf("VmMach_SharedProcFinish: freeing process's allocVector\n");
  5556.     if (debugVmStubs) {
  5557.     printf("VmMach_SharedProcFinish: freeing process's allocVector %x\n",
  5558.         procPtr->vmPtr->machPtr->sharedData.allocVector);
  5559.     }
  5560.     free((Address)procPtr->vmPtr->machPtr->sharedData.allocVector);
  5561.     procPtr->vmPtr->machPtr->sharedData.allocVector = (int *)NIL;
  5562. }
  5563.  
  5564. /*
  5565.  * ----------------------------------------------------------------------------
  5566.  *
  5567.  * VmMach_CopySharedMem --
  5568.  *
  5569.  *      Copies machine-dependent shared memory data structures to handle
  5570.  *      a fork.
  5571.  *
  5572.  * Results:
  5573.  *      None.
  5574.  *
  5575.  * Side effects:
  5576.  *      The new process gets a copy of the shared memory structures.
  5577.  *
  5578.  * ----------------------------------------------------------------------------
  5579.  */
  5580. void
  5581. VmMach_CopySharedMem(parentProcPtr, childProcPtr)
  5582.     Proc_ControlBlock   *parentProcPtr; /* Parent process. */
  5583.     Proc_ControlBlock   *childProcPtr;  /* Child process. */
  5584. {
  5585.     VmMach_SharedData   *childSharedData =
  5586.             &childProcPtr->vmPtr->machPtr->sharedData;
  5587.     VmMach_SharedData   *parentSharedData =
  5588.             &parentProcPtr->vmPtr->machPtr->sharedData;
  5589.  
  5590.     VmMach_SharedProcStart(childProcPtr);
  5591.  
  5592.     bcopy((Address)parentSharedData->allocVector,
  5593.         (Address)childSharedData->allocVector,
  5594.             VMMACH_SHARED_NUM_BLOCKS*sizeof(int));
  5595.     childSharedData->allocFirstFree = parentSharedData->allocFirstFree;
  5596. }
  5597.  
  5598. /*
  5599.  * ----------------------------------------------------------------------------
  5600.  *
  5601.  * VmMach_CopySharedMem --
  5602.  *
  5603.  *      Copies machine-dependent shared memory data structures to handle
  5604.  *      a fork.
  5605.  *
  5606.  * Results:
  5607.  *      None. (This routine is stubbed out for the sun4.
  5608.  *
  5609.  * Side effects:
  5610.  *      None.
  5611.  *
  5612.  * ----------------------------------------------------------------------------
  5613.  */
  5614. /*ARGSUSED*/
  5615. void
  5616. VmMachTracePMEG(pmeg)
  5617. int pmeg;
  5618. {
  5619.     panic("VmMachTracePMEG called.\n");
  5620. }
  5621.  
  5622. /*
  5623.  * ----------------------------------------------------------------------------
  5624.  *
  5625.  * VmMach_LockCachePage --
  5626.  *
  5627.  *      Perform machine dependent locking of a kernel resident file cache
  5628.  *    page.
  5629.  *
  5630.  * Results:
  5631.  *      None.
  5632.  *
  5633.  * Side effects:
  5634.  *
  5635.  * ----------------------------------------------------------------------------
  5636.  */
  5637. void
  5638. VmMach_LockCachePage(kernelAddress)
  5639.     Address    kernelAddress;    /* Address on page to lock. */
  5640. {
  5641.     register  Vm_VirtAddr    virtAddr;
  5642.     register  VMMACH_SEG_NUM    *segTablePtr, pmeg;
  5643.     register  int        hardSeg;
  5644.     Vm_PTE    *ptePtr;
  5645.     VmMachPTE        hardPTE;
  5646.     /*
  5647.      * Ignore pages not in cache pmeg range.
  5648.      */
  5649.     if (!IN_FILE_CACHE_SEG(kernelAddress)) {
  5650.     return;
  5651.     }
  5652.  
  5653.     MASTER_LOCK(vmMachMutexPtr);
  5654.  
  5655.     pmeg = VmMachGetSegMap(kernelAddress);
  5656.     if (pmeg == VMMACH_INV_PMEG) {
  5657.     int    oldContext, i;
  5658.     unsigned int a;
  5659.     /*
  5660.      *  If not a valid PMEG install a new pmeg and load its mapping. 
  5661.      */
  5662.     virtAddr.segPtr = vm_SysSegPtr;
  5663.     virtAddr.page = ((unsigned int) kernelAddress) >> VMMACH_PAGE_SHIFT;
  5664.     virtAddr.offset = 0;
  5665.     virtAddr.flags = 0;
  5666.     virtAddr.sharedPtr = (Vm_SegProcList *) NIL;
  5667.     
  5668.     hardSeg = PageToOffSeg(virtAddr.page, (&virtAddr));
  5669.     segTablePtr = (VMMACH_SEG_NUM *) 
  5670.                 GetHardSegPtr(vm_SysSegPtr->machPtr, hardSeg);
  5671.     if (*segTablePtr != VMMACH_INV_PMEG) {
  5672.         panic("VmMach_LockCachePage: Bad segTable entry.\n");
  5673.     }
  5674.     *segTablePtr = pmeg = PMEGGet(vm_SysSegPtr, hardSeg, 0);
  5675.     /*
  5676.      * Have to propagate the PMEG to all contexts.
  5677.      */
  5678.     oldContext = VmMachGetContextReg();
  5679.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  5680.         VmMachSetContextReg(i);
  5681.         VmMachSetSegMap(kernelAddress, pmeg);
  5682.     }
  5683.     VmMachSetContextReg(oldContext);
  5684.     /*
  5685.      * Reload the entire PMEG.
  5686.      */
  5687.     a = (hardSeg << VMMACH_SEG_SHIFT);
  5688.     for (i = 0; i < VMMACH_NUM_PAGES_PER_SEG_INT; i++ ) { 
  5689.         ptePtr = VmGetPTEPtr(vm_SysSegPtr, (a >> VMMACH_PAGE_SHIFT));
  5690.         if ((*ptePtr & VM_PHYS_RES_BIT)) {
  5691.         hardPTE = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | 
  5692.                 VirtToPhysPage(Vm_GetPageFrame(*ptePtr));
  5693.         SET_ALL_PAGE_MAP(a, hardPTE);
  5694.         if (pmeg==VMMACH_INV_PMEG) {
  5695.             panic("Invalid pmeg\n");
  5696.         }
  5697.         pmegArray[pmeg].pageCount++;
  5698.          }
  5699.          a += VMMACH_PAGE_SIZE_INT;
  5700.     }
  5701.     }
  5702.     pmegArray[pmeg].lockCount++;
  5703.  
  5704.     MASTER_UNLOCK(vmMachMutexPtr);
  5705.     return;
  5706. }
  5707.  
  5708. /*
  5709.  * ----------------------------------------------------------------------------
  5710.  *
  5711.  * VmMach_UnlockCachePage --
  5712.  *
  5713.  *      Perform machine dependent unlocking of a kernel resident page.
  5714.  *
  5715.  * Results:
  5716.  *      None.
  5717.  *
  5718.  * Side effects:
  5719.  *
  5720.  * ----------------------------------------------------------------------------
  5721.  */
  5722. void
  5723. VmMach_UnlockCachePage(kernelAddress)
  5724.     Address    kernelAddress;    /* Address on page to unlock. */
  5725. {
  5726.     register  VMMACH_SEG_NUM    pmeg;
  5727.  
  5728.     if (!IN_FILE_CACHE_SEG(kernelAddress)) {
  5729.     return;
  5730.     }
  5731.  
  5732.     MASTER_LOCK(vmMachMutexPtr);
  5733.  
  5734.     pmeg = VmMachGetSegMap(kernelAddress);
  5735.  
  5736.     pmegArray[pmeg].lockCount--;
  5737.     if (pmegArray[pmeg].lockCount < 0) {
  5738.     panic("VmMach_UnlockCachePage lockCount < 0\n");
  5739.     }
  5740.  
  5741.     MASTER_UNLOCK(vmMachMutexPtr);
  5742.     return;
  5743. }
  5744.